[PATCH] Replace merge-base implementation

The old implementation was a nice algorithm, but, unfortunately, it could
be confused in some cases and would not necessarily do the obvious thing
if one argument was decended from the other. This version fixes that by
changing the criterion to the most recent common ancestor.

Signed-Off-By: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Daniel Barkalow 2005-04-23 18:47:23 -07:00 committed by Linus Torvalds
parent 8237b1854c
commit b6b15db3f4

View File

@ -5,67 +5,63 @@
static struct commit *process_list(struct commit_list **list_p, int this_mark, static struct commit *process_list(struct commit_list **list_p, int this_mark,
int other_mark) int other_mark)
{ {
struct commit_list *parent, *temp; struct commit *item = (*list_p)->item;
struct commit_list *posn = *list_p;
*list_p = NULL; if (item->object.flags & this_mark) {
while (posn) { /*
parse_commit(posn->item); printf("%d already seen %s %x\n",
if (posn->item->object.flags & this_mark) { this_mark
/* sha1_to_hex(posn->parent->sha1),
printf("%d already seen %s %x\n", posn->parent->flags);
this_mark */
sha1_to_hex(posn->parent->sha1), /* do nothing; this indicates that this side
posn->parent->flags); * split and reformed, and we only need to
*/ * mark it once.
/* do nothing; this indicates that this side */
* split and reformed, and we only need to *list_p = (*list_p)->next;
* mark it once. } else if (item->object.flags & other_mark) {
*/ return item;
} else if (posn->item->object.flags & other_mark) { } else {
return posn->item; /*
} else { printf("%d based on %s\n",
/* this_mark,
printf("%d based on %s\n", sha1_to_hex(posn->parent->sha1));
this_mark, */
sha1_to_hex(posn->parent->sha1)); pop_most_recent_commit(list_p);
*/ item->object.flags |= this_mark;
posn->item->object.flags |= this_mark;
parent = posn->item->parents;
while (parent) {
temp = malloc(sizeof(struct commit_list));
temp->next = *list_p;
temp->item = parent->item;
*list_p = temp;
parent = parent->next;
}
}
posn = posn->next;
} }
return NULL; return NULL;
} }
struct commit *common_ancestor(struct commit *rev1, struct commit *rev2) struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)
{ {
struct commit_list *rev1list = malloc(sizeof(struct commit_list)); struct commit_list *rev1list = NULL;
struct commit_list *rev2list = malloc(sizeof(struct commit_list)); struct commit_list *rev2list = NULL;
rev1list->item = rev1; commit_list_insert(rev1, &rev1list);
rev1list->next = NULL; commit_list_insert(rev2, &rev2list);
rev2list->item = rev2; parse_commit(rev1);
rev2list->next = NULL; parse_commit(rev2);
while (rev1list || rev2list) { while (rev1list || rev2list) {
struct commit *ret; struct commit *ret;
ret = process_list(&rev1list, 0x1, 0x2); if (!rev1list) {
if (ret) { // process 2
/* XXXX free lists */ ret = process_list(&rev2list, 0x2, 0x1);
return ret; } else if (!rev2list) {
// process 1
ret = process_list(&rev1list, 0x1, 0x2);
} else if (rev1list->item->date < rev2list->item->date) {
// process 2
ret = process_list(&rev2list, 0x2, 0x1);
} else {
// process 1
ret = process_list(&rev1list, 0x1, 0x2);
} }
ret = process_list(&rev2list, 0x2, 0x1);
if (ret) { if (ret) {
/* XXXX free lists */ free_commit_list(rev1list);
free_commit_list(rev2list);
return ret; return ret;
} }
} }