blob: 6f3941f2a49ce51ee295158a4d78f5c80c1afeb7 [file] [log] [blame]
Peter Hagervallbaffc0e2007-07-15 01:14:45 +02001#include "builtin.h"
Linus Torvalds66834632005-04-17 12:18:17 -07002#include "cache.h"
Brandon Williamsb2141fc2017-06-14 11:07:36 -07003#include "config.h"
Daniel Barkalowb5039db2005-04-18 11:39:48 -07004#include "commit.h"
Junio C Hamanod96855f2013-10-23 16:47:32 -07005#include "refs.h"
6#include "diff.h"
7#include "revision.h"
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +02008#include "parse-options.h"
Stefan Beller2122f672018-06-28 18:21:58 -07009#include "repository.h"
Derrick Stolee64043552018-07-20 16:33:04 +000010#include "commit-reach.h"
Linus Torvalds66834632005-04-17 12:18:17 -070011
Christian Couder53eda892008-07-30 07:04:14 +020012static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
Johannes Schindelin52cab8a2006-06-29 15:16:46 +020013{
Martin Ågrena452d0f2017-11-07 21:39:44 +010014 struct commit_list *result, *r;
Christian Couder53eda892008-07-30 07:04:14 +020015
Junio C Hamano2ce406c2014-10-30 12:20:44 -070016 result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
Johannes Schindelin52cab8a2006-06-29 15:16:46 +020017
18 if (!result)
19 return 1;
20
Martin Ågrena452d0f2017-11-07 21:39:44 +010021 for (r = result; r; r = r->next) {
22 printf("%s\n", oid_to_hex(&r->item->object.oid));
Junio C Hamano9585e402005-08-23 21:08:59 -070023 if (!show_all)
Martin Ågrena452d0f2017-11-07 21:39:44 +010024 break;
Junio C Hamano9585e402005-08-23 21:08:59 -070025 }
Johannes Schindelin52cab8a2006-06-29 15:16:46 +020026
Martin Ågrena452d0f2017-11-07 21:39:44 +010027 free_commit_list(result);
Junio C Hamano9585e402005-08-23 21:08:59 -070028 return 0;
Linus Torvalds66834632005-04-17 12:18:17 -070029}
30
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +020031static const char * const merge_base_usage[] = {
Alex Henrie9c9b4f22015-01-13 00:44:47 -070032 N_("git merge-base [-a | --all] <commit> <commit>..."),
33 N_("git merge-base [-a | --all] --octopus <commit>..."),
Junio C Hamano34f51302012-09-11 11:35:26 -070034 N_("git merge-base --is-ancestor <commit> <commit>"),
Ævar Arnfjörð Bjarmason8f5f2f62022-10-13 17:39:12 +020035 N_("git merge-base --independent <commit>..."),
Junio C Hamanod96855f2013-10-23 16:47:32 -070036 N_("git merge-base --fork-point <ref> [<commit>]"),
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +020037 NULL
38};
Junio C Hamano9585e402005-08-23 21:08:59 -070039
Christian Couderdf57acc2008-07-29 07:42:53 +020040static struct commit *get_commit_reference(const char *arg)
41{
brian m. carlsond0ae9102017-02-21 23:47:36 +000042 struct object_id revkey;
Christian Couderdf57acc2008-07-29 07:42:53 +020043 struct commit *r;
44
brian m. carlsond0ae9102017-02-21 23:47:36 +000045 if (get_oid(arg, &revkey))
Christian Couderdf57acc2008-07-29 07:42:53 +020046 die("Not a valid object name %s", arg);
Stefan Beller2122f672018-06-28 18:21:58 -070047 r = lookup_commit_reference(the_repository, &revkey);
Christian Couderdf57acc2008-07-29 07:42:53 +020048 if (!r)
49 die("Not a valid commit name %s", arg);
50
51 return r;
52}
53
Junio C Hamanoe2f5df42013-12-30 11:37:49 -080054static int handle_independent(int count, const char **args)
Jonathan Niederaa8f98c2010-08-17 02:01:15 -050055{
Martin Ågrena452d0f2017-11-07 21:39:44 +010056 struct commit_list *revs = NULL, *rev;
Jonathan Niederaa8f98c2010-08-17 02:01:15 -050057 int i;
58
Junio C Hamanoe2f5df42013-12-30 11:37:49 -080059 for (i = count - 1; i >= 0; i--)
60 commit_list_insert(get_commit_reference(args[i]), &revs);
61
Martin Ågren4da72642017-11-07 21:39:45 +010062 reduce_heads_replace(&revs);
Martin Ågrena452d0f2017-11-07 21:39:44 +010063
64 if (!revs)
Junio C Hamanoe2f5df42013-12-30 11:37:49 -080065 return 1;
66
Martin Ågrena452d0f2017-11-07 21:39:44 +010067 for (rev = revs; rev; rev = rev->next)
68 printf("%s\n", oid_to_hex(&rev->item->object.oid));
69
70 free_commit_list(revs);
Junio C Hamanoe2f5df42013-12-30 11:37:49 -080071 return 0;
72}
73
74static int handle_octopus(int count, const char **args, int show_all)
75{
76 struct commit_list *revs = NULL;
Martin Ågrena452d0f2017-11-07 21:39:44 +010077 struct commit_list *result, *rev;
Junio C Hamanoe2f5df42013-12-30 11:37:49 -080078 int i;
Jonathan Niedera1e0ad72010-08-17 02:01:54 -050079
80 for (i = count - 1; i >= 0; i--)
Jonathan Niederaa8f98c2010-08-17 02:01:15 -050081 commit_list_insert(get_commit_reference(args[i]), &revs);
Jonathan Niedera1e0ad72010-08-17 02:01:54 -050082
Martin Ågren4da72642017-11-07 21:39:45 +010083 result = get_octopus_merge_bases(revs);
84 free_commit_list(revs);
85 reduce_heads_replace(&result);
Jonathan Niederaa8f98c2010-08-17 02:01:15 -050086
87 if (!result)
88 return 1;
89
Martin Ågrena452d0f2017-11-07 21:39:44 +010090 for (rev = result; rev; rev = rev->next) {
91 printf("%s\n", oid_to_hex(&rev->item->object.oid));
Jonathan Niederaa8f98c2010-08-17 02:01:15 -050092 if (!show_all)
Martin Ågrena452d0f2017-11-07 21:39:44 +010093 break;
Jonathan Niederaa8f98c2010-08-17 02:01:15 -050094 }
95
Martin Ågrena452d0f2017-11-07 21:39:44 +010096 free_commit_list(result);
Jonathan Niederaa8f98c2010-08-17 02:01:15 -050097 return 0;
98}
99
Junio C Hamano5907cda2012-08-30 14:52:20 -0700100static int handle_is_ancestor(int argc, const char **argv)
101{
102 struct commit *one, *two;
103
104 if (argc != 2)
105 die("--is-ancestor takes exactly two commits");
106 one = get_commit_reference(argv[0]);
107 two = get_commit_reference(argv[1]);
108 if (in_merge_bases(one, two))
109 return 0;
110 else
111 return 1;
112}
113
Junio C Hamanod96855f2013-10-23 16:47:32 -0700114static int handle_fork_point(int argc, const char **argv)
115{
brian m. carlsond0ae9102017-02-21 23:47:36 +0000116 struct object_id oid;
Pratik Karki103148a2018-09-04 15:00:08 -0700117 struct commit *derived, *fork_point;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700118 const char *commitname;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700119
Junio C Hamanod96855f2013-10-23 16:47:32 -0700120 commitname = (argc == 2) ? argv[1] : "HEAD";
brian m. carlsond0ae9102017-02-21 23:47:36 +0000121 if (get_oid(commitname, &oid))
Junio C Hamanod96855f2013-10-23 16:47:32 -0700122 die("Not a valid object name: '%s'", commitname);
123
Stefan Beller2122f672018-06-28 18:21:58 -0700124 derived = lookup_commit_reference(the_repository, &oid);
Junio C Hamanod96855f2013-10-23 16:47:32 -0700125
Junio C Hamanof08132f2019-12-09 10:51:47 -0800126 fork_point = get_fork_point(argv[0], derived);
Jeff King4f214542016-10-12 16:10:40 -0400127
Pratik Karki103148a2018-09-04 15:00:08 -0700128 if (!fork_point)
129 return 1;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700130
Pratik Karki103148a2018-09-04 15:00:08 -0700131 printf("%s\n", oid_to_hex(&fork_point->object.oid));
132 return 0;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700133}
134
Junio C Hamano71dfbf22007-01-09 00:50:02 -0800135int cmd_merge_base(int argc, const char **argv, const char *prefix)
Linus Torvalds66834632005-04-17 12:18:17 -0700136{
Christian Couder53eda892008-07-30 07:04:14 +0200137 struct commit **rev;
138 int rev_nr = 0;
Junio C Hamano71dfbf22007-01-09 00:50:02 -0800139 int show_all = 0;
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700140 int cmdmode = 0;
Ævar Arnfjörð Bjarmasone69fe2e2022-03-04 19:32:05 +0100141 int ret;
Linus Torvalds66834632005-04-17 12:18:17 -0700142
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +0200143 struct option options[] = {
Stefan Bellerd5d09d42013-08-03 13:51:19 +0200144 OPT_BOOL('a', "all", &show_all, N_("output all common ancestors")),
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700145 OPT_CMDMODE(0, "octopus", &cmdmode,
146 N_("find ancestors for a single n-way merge"), 'o'),
147 OPT_CMDMODE(0, "independent", &cmdmode,
148 N_("list revs not reachable from others"), 'r'),
149 OPT_CMDMODE(0, "is-ancestor", &cmdmode,
150 N_("is the first one ancestor of the other?"), 'a'),
Junio C Hamanod96855f2013-10-23 16:47:32 -0700151 OPT_CMDMODE(0, "fork-point", &cmdmode,
152 N_("find where <commit> forked from reflog of <ref>"), 'f'),
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +0200153 OPT_END()
154 };
155
Johannes Schindelinef90d6d2008-05-14 18:46:53 +0100156 git_config(git_default_config, NULL);
Stephen Boyd37782922009-05-23 11:53:12 -0700157 argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
Jonathan Niederaa8f98c2010-08-17 02:01:15 -0500158
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700159 if (cmdmode == 'a') {
160 if (argc < 2)
161 usage_with_options(merge_base_usage, options);
162 if (show_all)
Jean-Noël Avilaa6993672022-01-31 22:07:46 +0000163 die(_("options '%s' and '%s' cannot be used together"),
164 "--is-ancestor", "--all");
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700165 return handle_is_ancestor(argc, argv);
166 }
167
168 if (cmdmode == 'r' && show_all)
Jean-Noël Avilaa6993672022-01-31 22:07:46 +0000169 die(_("options '%s' and '%s' cannot be used together"),
170 "--independent", "--all");
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700171
Junio C Hamanod5d16782014-01-10 10:33:32 -0800172 if (cmdmode == 'o')
Junio C Hamanoe2f5df42013-12-30 11:37:49 -0800173 return handle_octopus(argc, argv, show_all);
Junio C Hamanod5d16782014-01-10 10:33:32 -0800174
175 if (cmdmode == 'r')
Junio C Hamanoe2f5df42013-12-30 11:37:49 -0800176 return handle_independent(argc, argv);
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700177
Junio C Hamanod96855f2013-10-23 16:47:32 -0700178 if (cmdmode == 'f') {
179 if (argc < 1 || 2 < argc)
180 usage_with_options(merge_base_usage, options);
181 return handle_fork_point(argc, argv);
182 }
183
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700184 if (argc < 2)
185 usage_with_options(merge_base_usage, options);
Jonathan Niederaa8f98c2010-08-17 02:01:15 -0500186
Jeff Kingb32fa952016-02-22 17:44:25 -0500187 ALLOC_ARRAY(rev, argc);
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +0200188 while (argc-- > 0)
189 rev[rev_nr++] = get_commit_reference(*argv++);
Ævar Arnfjörð Bjarmasone69fe2e2022-03-04 19:32:05 +0100190 ret = show_merge_base(rev, rev_nr, show_all);
191 free(rev);
192 return ret;
Linus Torvalds66834632005-04-17 12:18:17 -0700193}