]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/merge-base.c
object-name.h: move declarations for object-name.c functions from cache.h
[thirdparty/git.git] / builtin / merge-base.c
CommitLineData
baffc0e7 1#include "builtin.h"
6683463e 2#include "cache.h"
b2141fc1 3#include "config.h"
b5039db6 4#include "commit.h"
f394e093 5#include "gettext.h"
41771fa4 6#include "hex.h"
d96855ff
JH
7#include "refs.h"
8#include "diff.h"
9#include "revision.h"
dabab1d6 10#include "object-name.h"
e5d1a4df 11#include "parse-options.h"
2122f675 12#include "repository.h"
64043556 13#include "commit-reach.h"
6683463e 14
53eda89b 15static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
52cab8a0 16{
a452d0f4 17 struct commit_list *result, *r;
53eda89b 18
cb338c23
ÆAB
19 result = repo_get_merge_bases_many_dirty(the_repository, rev[0],
20 rev_nr - 1, rev + 1);
52cab8a0
JS
21
22 if (!result)
23 return 1;
24
a452d0f4
25 for (r = result; r; r = r->next) {
26 printf("%s\n", oid_to_hex(&r->item->object.oid));
9585e406 27 if (!show_all)
a452d0f4 28 break;
9585e406 29 }
52cab8a0 30
a452d0f4 31 free_commit_list(result);
9585e406 32 return 0;
6683463e
LT
33}
34
e5d1a4df 35static const char * const merge_base_usage[] = {
9c9b4f2f
AH
36 N_("git merge-base [-a | --all] <commit> <commit>..."),
37 N_("git merge-base [-a | --all] --octopus <commit>..."),
34f5130a 38 N_("git merge-base --is-ancestor <commit> <commit>"),
8f5f2f64 39 N_("git merge-base --independent <commit>..."),
d96855ff 40 N_("git merge-base --fork-point <ref> [<commit>]"),
e5d1a4df
PH
41 NULL
42};
9585e406 43
df57accb
CC
44static struct commit *get_commit_reference(const char *arg)
45{
d0ae910a 46 struct object_id revkey;
df57accb
CC
47 struct commit *r;
48
d850b7a5 49 if (repo_get_oid(the_repository, arg, &revkey))
df57accb 50 die("Not a valid object name %s", arg);
2122f675 51 r = lookup_commit_reference(the_repository, &revkey);
df57accb
CC
52 if (!r)
53 die("Not a valid commit name %s", arg);
54
55 return r;
56}
57
e2f5df42 58static int handle_independent(int count, const char **args)
aa8f98c1 59{
a452d0f4 60 struct commit_list *revs = NULL, *rev;
aa8f98c1
JN
61 int i;
62
e2f5df42
JH
63 for (i = count - 1; i >= 0; i--)
64 commit_list_insert(get_commit_reference(args[i]), &revs);
65
4da72644 66 reduce_heads_replace(&revs);
a452d0f4
67
68 if (!revs)
e2f5df42
JH
69 return 1;
70
a452d0f4
71 for (rev = revs; rev; rev = rev->next)
72 printf("%s\n", oid_to_hex(&rev->item->object.oid));
73
74 free_commit_list(revs);
e2f5df42
JH
75 return 0;
76}
77
78static int handle_octopus(int count, const char **args, int show_all)
79{
80 struct commit_list *revs = NULL;
a452d0f4 81 struct commit_list *result, *rev;
e2f5df42 82 int i;
a1e0ad78
JN
83
84 for (i = count - 1; i >= 0; i--)
aa8f98c1 85 commit_list_insert(get_commit_reference(args[i]), &revs);
a1e0ad78 86
4da72644
87 result = get_octopus_merge_bases(revs);
88 free_commit_list(revs);
89 reduce_heads_replace(&result);
aa8f98c1
JN
90
91 if (!result)
92 return 1;
93
a452d0f4
94 for (rev = result; rev; rev = rev->next) {
95 printf("%s\n", oid_to_hex(&rev->item->object.oid));
aa8f98c1 96 if (!show_all)
a452d0f4 97 break;
aa8f98c1
JN
98 }
99
a452d0f4 100 free_commit_list(result);
aa8f98c1
JN
101 return 0;
102}
103
5907cda1
JH
104static int handle_is_ancestor(int argc, const char **argv)
105{
106 struct commit *one, *two;
107
108 if (argc != 2)
109 die("--is-ancestor takes exactly two commits");
110 one = get_commit_reference(argv[0]);
111 two = get_commit_reference(argv[1]);
cb338c23 112 if (repo_in_merge_bases(the_repository, one, two))
5907cda1
JH
113 return 0;
114 else
115 return 1;
116}
117
d96855ff
JH
118static int handle_fork_point(int argc, const char **argv)
119{
d0ae910a 120 struct object_id oid;
103148aa 121 struct commit *derived, *fork_point;
d96855ff 122 const char *commitname;
d96855ff 123
d96855ff 124 commitname = (argc == 2) ? argv[1] : "HEAD";
d850b7a5 125 if (repo_get_oid(the_repository, commitname, &oid))
d96855ff
JH
126 die("Not a valid object name: '%s'", commitname);
127
2122f675 128 derived = lookup_commit_reference(the_repository, &oid);
d96855ff 129
f08132f8 130 fork_point = get_fork_point(argv[0], derived);
4f21454b 131
103148aa
PK
132 if (!fork_point)
133 return 1;
d96855ff 134
103148aa
PK
135 printf("%s\n", oid_to_hex(&fork_point->object.oid));
136 return 0;
d96855ff
JH
137}
138
71dfbf22 139int cmd_merge_base(int argc, const char **argv, const char *prefix)
6683463e 140{
53eda89b
CC
141 struct commit **rev;
142 int rev_nr = 0;
71dfbf22 143 int show_all = 0;
16e57aec 144 int cmdmode = 0;
e69fe2e4 145 int ret;
6683463e 146
e5d1a4df 147 struct option options[] = {
d5d09d47 148 OPT_BOOL('a', "all", &show_all, N_("output all common ancestors")),
16e57aec
JH
149 OPT_CMDMODE(0, "octopus", &cmdmode,
150 N_("find ancestors for a single n-way merge"), 'o'),
151 OPT_CMDMODE(0, "independent", &cmdmode,
152 N_("list revs not reachable from others"), 'r'),
153 OPT_CMDMODE(0, "is-ancestor", &cmdmode,
154 N_("is the first one ancestor of the other?"), 'a'),
d96855ff
JH
155 OPT_CMDMODE(0, "fork-point", &cmdmode,
156 N_("find where <commit> forked from reflog of <ref>"), 'f'),
e5d1a4df
PH
157 OPT_END()
158 };
53eda89b 159
e5d1a4df 160 git_config(git_default_config, NULL);
37782920 161 argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
16e57aec
JH
162
163 if (cmdmode == 'a') {
164 if (argc < 2)
165 usage_with_options(merge_base_usage, options);
166 if (show_all)
a699367b
JNA
167 die(_("options '%s' and '%s' cannot be used together"),
168 "--is-ancestor", "--all");
5907cda1 169 return handle_is_ancestor(argc, argv);
16e57aec 170 }
aa8f98c1 171
16e57aec 172 if (cmdmode == 'r' && show_all)
a699367b
JNA
173 die(_("options '%s' and '%s' cannot be used together"),
174 "--independent", "--all");
16e57aec 175
d5d1678b 176 if (cmdmode == 'o')
e2f5df42 177 return handle_octopus(argc, argv, show_all);
d5d1678b
JH
178
179 if (cmdmode == 'r')
e2f5df42 180 return handle_independent(argc, argv);
16e57aec 181
d96855ff
JH
182 if (cmdmode == 'f') {
183 if (argc < 1 || 2 < argc)
184 usage_with_options(merge_base_usage, options);
185 return handle_fork_point(argc, argv);
186 }
187
16e57aec
JH
188 if (argc < 2)
189 usage_with_options(merge_base_usage, options);
aa8f98c1 190
b32fa95f 191 ALLOC_ARRAY(rev, argc);
e5d1a4df
PH
192 while (argc-- > 0)
193 rev[rev_nr++] = get_commit_reference(*argv++);
e69fe2e4
ÆAB
194 ret = show_merge_base(rev, rev_nr, show_all);
195 free(rev);
196 return ret;
6683463e 197}