Skip to content

Commit 103148a

Browse files
prertikgitster
authored andcommitted
merge-base --fork-point: extract libified function
We need this functionality in the builtin rebase. Note: to make this function truly reusable, we have to switch the call get_merges_many_dirty() to get_merges_many() because we want the commit flags to be reset (otherwise, subsequent get_merge_bases() calls would obtain incorrect results). This did not matter when the function was called in `git rev-parse --fork-point` because in that command, the process definitely did not traverse any commits before exiting. Signed-off-by: Pratik Karki <[email protected]> Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3c3588c commit 103148a

File tree

3 files changed

+89
-75
lines changed

3 files changed

+89
-75
lines changed

builtin/merge-base.c

Lines changed: 6 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -110,54 +110,12 @@ static int handle_is_ancestor(int argc, const char **argv)
110110
return 1;
111111
}
112112

113-
struct rev_collect {
114-
struct commit **commit;
115-
int nr;
116-
int alloc;
117-
unsigned int initial : 1;
118-
};
119-
120-
static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
121-
{
122-
struct commit *commit;
123-
124-
if (is_null_oid(oid))
125-
return;
126-
127-
commit = lookup_commit(the_repository, oid);
128-
if (!commit ||
129-
(commit->object.flags & TMP_MARK) ||
130-
parse_commit(commit))
131-
return;
132-
133-
ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
134-
revs->commit[revs->nr++] = commit;
135-
commit->object.flags |= TMP_MARK;
136-
}
137-
138-
static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
139-
const char *ident, timestamp_t timestamp,
140-
int tz, const char *message, void *cbdata)
141-
{
142-
struct rev_collect *revs = cbdata;
143-
144-
if (revs->initial) {
145-
revs->initial = 0;
146-
add_one_commit(ooid, revs);
147-
}
148-
add_one_commit(noid, revs);
149-
return 0;
150-
}
151-
152113
static int handle_fork_point(int argc, const char **argv)
153114
{
154115
struct object_id oid;
155116
char *refname;
117+
struct commit *derived, *fork_point;
156118
const char *commitname;
157-
struct rev_collect revs;
158-
struct commit *derived;
159-
struct commit_list *bases;
160-
int i, ret = 0;
161119

162120
switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
163121
case 0:
@@ -173,41 +131,14 @@ static int handle_fork_point(int argc, const char **argv)
173131
die("Not a valid object name: '%s'", commitname);
174132

175133
derived = lookup_commit_reference(the_repository, &oid);
176-
memset(&revs, 0, sizeof(revs));
177-
revs.initial = 1;
178-
for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
179134

180-
if (!revs.nr && !get_oid(refname, &oid))
181-
add_one_commit(&oid, &revs);
135+
fork_point = get_fork_point(refname, derived);
182136

183-
for (i = 0; i < revs.nr; i++)
184-
revs.commit[i]->object.flags &= ~TMP_MARK;
185-
186-
bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);
187-
188-
/*
189-
* There should be one and only one merge base, when we found
190-
* a common ancestor among reflog entries.
191-
*/
192-
if (!bases || bases->next) {
193-
ret = 1;
194-
goto cleanup_return;
195-
}
196-
197-
/* And the found one must be one of the reflog entries */
198-
for (i = 0; i < revs.nr; i++)
199-
if (&bases->item->object == &revs.commit[i]->object)
200-
break; /* found */
201-
if (revs.nr <= i) {
202-
ret = 1; /* not found */
203-
goto cleanup_return;
204-
}
205-
206-
printf("%s\n", oid_to_hex(&bases->item->object.oid));
137+
if (!fork_point)
138+
return 1;
207139

208-
cleanup_return:
209-
free_commit_list(bases);
210-
return ret;
140+
printf("%s\n", oid_to_hex(&fork_point->object.oid));
141+
return 0;
211142
}
212143

213144
int cmd_merge_base(int argc, const char **argv, const char *prefix)

commit.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "sha1-lookup.h"
1818
#include "wt-status.h"
1919
#include "advice.h"
20+
#include "refs.h"
2021

2122
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
2223

@@ -958,6 +959,86 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
958959
return result;
959960
}
960961

962+
struct rev_collect {
963+
struct commit **commit;
964+
int nr;
965+
int alloc;
966+
unsigned int initial : 1;
967+
};
968+
969+
static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
970+
{
971+
struct commit *commit;
972+
973+
if (is_null_oid(oid))
974+
return;
975+
976+
commit = lookup_commit(the_repository, oid);
977+
if (!commit ||
978+
(commit->object.flags & TMP_MARK) ||
979+
parse_commit(commit))
980+
return;
981+
982+
ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
983+
revs->commit[revs->nr++] = commit;
984+
commit->object.flags |= TMP_MARK;
985+
}
986+
987+
static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
988+
const char *ident, timestamp_t timestamp,
989+
int tz, const char *message, void *cbdata)
990+
{
991+
struct rev_collect *revs = cbdata;
992+
993+
if (revs->initial) {
994+
revs->initial = 0;
995+
add_one_commit(ooid, revs);
996+
}
997+
add_one_commit(noid, revs);
998+
return 0;
999+
}
1000+
1001+
struct commit *get_fork_point(const char *refname, struct commit *commit)
1002+
{
1003+
struct object_id oid;
1004+
struct rev_collect revs;
1005+
struct commit_list *bases;
1006+
int i;
1007+
struct commit *ret = NULL;
1008+
1009+
memset(&revs, 0, sizeof(revs));
1010+
revs.initial = 1;
1011+
for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
1012+
1013+
if (!revs.nr && !get_oid(refname, &oid))
1014+
add_one_commit(&oid, &revs);
1015+
1016+
for (i = 0; i < revs.nr; i++)
1017+
revs.commit[i]->object.flags &= ~TMP_MARK;
1018+
1019+
bases = get_merge_bases_many(commit, revs.nr, revs.commit);
1020+
1021+
/*
1022+
* There should be one and only one merge base, when we found
1023+
* a common ancestor among reflog entries.
1024+
*/
1025+
if (!bases || bases->next)
1026+
goto cleanup_return;
1027+
1028+
/* And the found one must be one of the reflog entries */
1029+
for (i = 0; i < revs.nr; i++)
1030+
if (&bases->item->object == &revs.commit[i]->object)
1031+
break; /* found */
1032+
if (revs.nr <= i)
1033+
goto cleanup_return;
1034+
1035+
ret = bases->item;
1036+
1037+
cleanup_return:
1038+
free_commit_list(bases);
1039+
return ret;
1040+
}
1041+
9611042
struct commit_list *get_octopus_merge_bases(struct commit_list *in)
9621043
{
9631044
struct commit_list *i, *j, *k, *ret = NULL;

commit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
211211
/* To be used only when object flags after this call no longer matter */
212212
extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
213213

214+
struct commit *get_fork_point(const char *refname, struct commit *commit);
215+
214216
/* largest positive number a signed 32-bit integer can contain */
215217
#define INFINITE_DEPTH 0x7fffffff
216218

0 commit comments

Comments
 (0)