blob: e3f8da13b69b8dbe6898bf71ee2b5df206179bd1 [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>..."),
Nguyễn Thái Ngọc Duyf037dbf2012-08-20 19:32:22 +070034 N_("git merge-base --independent <commit>..."),
Junio C Hamano34f51302012-09-11 11:35:26 -070035 N_("git merge-base --is-ancestor <commit> <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;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700117 char *refname;
Pratik Karki103148a2018-09-04 15:00:08 -0700118 struct commit *derived, *fork_point;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700119 const char *commitname;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700120
brian m. carlsoncca5fa62017-10-15 22:06:57 +0000121 switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
Junio C Hamanod96855f2013-10-23 16:47:32 -0700122 case 0:
123 die("No such ref: '%s'", argv[0]);
124 case 1:
125 break; /* good */
126 default:
127 die("Ambiguous refname: '%s'", argv[0]);
128 }
129
130 commitname = (argc == 2) ? argv[1] : "HEAD";
brian m. carlsond0ae9102017-02-21 23:47:36 +0000131 if (get_oid(commitname, &oid))
Junio C Hamanod96855f2013-10-23 16:47:32 -0700132 die("Not a valid object name: '%s'", commitname);
133
Stefan Beller2122f672018-06-28 18:21:58 -0700134 derived = lookup_commit_reference(the_repository, &oid);
Junio C Hamanod96855f2013-10-23 16:47:32 -0700135
Pratik Karki103148a2018-09-04 15:00:08 -0700136 fork_point = get_fork_point(refname, derived);
Jeff King4f214542016-10-12 16:10:40 -0400137
Pratik Karki103148a2018-09-04 15:00:08 -0700138 if (!fork_point)
139 return 1;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700140
Pratik Karki103148a2018-09-04 15:00:08 -0700141 printf("%s\n", oid_to_hex(&fork_point->object.oid));
142 return 0;
Junio C Hamanod96855f2013-10-23 16:47:32 -0700143}
144
Junio C Hamano71dfbf22007-01-09 00:50:02 -0800145int cmd_merge_base(int argc, const char **argv, const char *prefix)
Linus Torvalds66834632005-04-17 12:18:17 -0700146{
Christian Couder53eda892008-07-30 07:04:14 +0200147 struct commit **rev;
148 int rev_nr = 0;
Junio C Hamano71dfbf22007-01-09 00:50:02 -0800149 int show_all = 0;
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700150 int cmdmode = 0;
Linus Torvalds66834632005-04-17 12:18:17 -0700151
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +0200152 struct option options[] = {
Stefan Bellerd5d09d42013-08-03 13:51:19 +0200153 OPT_BOOL('a', "all", &show_all, N_("output all common ancestors")),
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700154 OPT_CMDMODE(0, "octopus", &cmdmode,
155 N_("find ancestors for a single n-way merge"), 'o'),
156 OPT_CMDMODE(0, "independent", &cmdmode,
157 N_("list revs not reachable from others"), 'r'),
158 OPT_CMDMODE(0, "is-ancestor", &cmdmode,
159 N_("is the first one ancestor of the other?"), 'a'),
Junio C Hamanod96855f2013-10-23 16:47:32 -0700160 OPT_CMDMODE(0, "fork-point", &cmdmode,
161 N_("find where <commit> forked from reflog of <ref>"), 'f'),
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +0200162 OPT_END()
163 };
164
Johannes Schindelinef90d6d2008-05-14 18:46:53 +0100165 git_config(git_default_config, NULL);
Stephen Boyd37782922009-05-23 11:53:12 -0700166 argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
Jonathan Niederaa8f98c2010-08-17 02:01:15 -0500167
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700168 if (cmdmode == 'a') {
169 if (argc < 2)
170 usage_with_options(merge_base_usage, options);
171 if (show_all)
172 die("--is-ancestor cannot be used with --all");
173 return handle_is_ancestor(argc, argv);
174 }
175
176 if (cmdmode == 'r' && show_all)
177 die("--independent cannot be used with --all");
178
Junio C Hamanod5d16782014-01-10 10:33:32 -0800179 if (cmdmode == 'o')
Junio C Hamanoe2f5df42013-12-30 11:37:49 -0800180 return handle_octopus(argc, argv, show_all);
Junio C Hamanod5d16782014-01-10 10:33:32 -0800181
182 if (cmdmode == 'r')
Junio C Hamanoe2f5df42013-12-30 11:37:49 -0800183 return handle_independent(argc, argv);
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700184
Junio C Hamanod96855f2013-10-23 16:47:32 -0700185 if (cmdmode == 'f') {
186 if (argc < 1 || 2 < argc)
187 usage_with_options(merge_base_usage, options);
188 return handle_fork_point(argc, argv);
189 }
190
Junio C Hamano16e57ae2013-10-23 16:10:25 -0700191 if (argc < 2)
192 usage_with_options(merge_base_usage, options);
Jonathan Niederaa8f98c2010-08-17 02:01:15 -0500193
Jeff Kingb32fa952016-02-22 17:44:25 -0500194 ALLOC_ARRAY(rev, argc);
Pierre Habouzite5d1a4d2008-10-02 14:59:19 +0200195 while (argc-- > 0)
196 rev[rev_nr++] = get_commit_reference(*argv++);
Christian Couder53eda892008-07-30 07:04:14 +0200197 return show_merge_base(rev, rev_nr, show_all);
Linus Torvalds66834632005-04-17 12:18:17 -0700198}