Skip to content

Commit f885cdb

Browse files
derrickstoleeKevin Willford
authored and
Kevin Willford
committed
commit: add generation to pop_most_recent_commit()
The method pop_most_recent_commit() is confusingly named, in that it pops the most-recent commit, but also adds that commit's parents to the list. This is used by a few commit walks, especially the one in ref_newer(). 'git push' uses ref_newer() to check if a force-push is necessary, and in the case of a force-push being needed, the current algorithm walks every reachable commit. This is especially severe in the case of an amended commit: they have the same parent, but we still walk to the very end of the graph! Add a 'min_generation' parameter to pop_most_recent_commit() to limit the commits that are walked to those with generation number at least 'min_generation'. This greatly reduces the number of commits walked by a force-push. There may be more work to improve this algorithm in the future, but for now this is enough for most cases. This direction has the benefit that it does not affect the non-force-push case at all. Future directions should consider improving that case as well. Signed-off-by: Derrick Stolee <[email protected]>
1 parent fbdfd6e commit f885cdb

File tree

6 files changed

+24
-8
lines changed

6 files changed

+24
-8
lines changed

commit.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,8 @@ void commit_list_sort_by_date(struct commit_list **list)
582582
}
583583

584584
struct commit *pop_most_recent_commit(struct commit_list **list,
585-
unsigned int mark)
585+
unsigned int mark,
586+
uint32_t min_generation)
586587
{
587588
struct commit *ret = pop_commit(list);
588589
struct commit_list *parents = ret->parents;
@@ -591,7 +592,9 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
591592
struct commit *commit = parents->item;
592593
if (!parse_commit(commit) && !(commit->object.flags & mark)) {
593594
commit->object.flags |= mark;
594-
commit_list_insert_by_date(commit, list);
595+
596+
if (commit->generation >= min_generation)
597+
commit_list_insert_by_date(commit, list);
595598
}
596599
parents = parents->next;
597600
}

commit.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,13 @@ extern const char *skip_blank_lines(const char *msg);
165165

166166
/** Removes the first commit from a list sorted by date, and adds all
167167
* of its parents.
168+
*
169+
* The parents are not added if their generation number is strictly
170+
* lower than min_generation.
168171
**/
169172
struct commit *pop_most_recent_commit(struct commit_list **list,
170-
unsigned int mark);
173+
unsigned int mark,
174+
uint32_t min_generation);
171175

172176
struct commit *pop_commit(struct commit_list **stack);
173177

fetch-pack.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,8 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
516516
while (complete && cutoff <= complete->item->date) {
517517
print_verbose(args, _("Marking %s as complete"),
518518
oid_to_hex(&complete->item->object.oid));
519-
pop_most_recent_commit(&complete, COMPLETE);
519+
pop_most_recent_commit(&complete, COMPLETE,
520+
GENERATION_NUMBER_ZERO);
520521
}
521522
}
522523

remote.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
18051805
struct commit *old_commit, *new_commit;
18061806
struct commit_list *list, *used;
18071807
int found = 0;
1808+
uint32_t min_generation;
18081809

18091810
/*
18101811
* Both new_commit and old_commit must be commit-ish and new_commit is descendant of
@@ -1822,13 +1823,18 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
18221823
return 0;
18231824
new_commit = (struct commit *) o;
18241825

1825-
if (parse_commit(new_commit) < 0)
1826+
if (parse_commit(new_commit) < 0 ||
1827+
parse_commit(old_commit) < 0)
18261828
return 0;
18271829

1830+
min_generation = old_commit->generation;
1831+
18281832
used = list = NULL;
18291833
commit_list_insert(new_commit, &list);
18301834
while (list) {
1831-
new_commit = pop_most_recent_commit(&list, TMP_MARK);
1835+
new_commit = pop_most_recent_commit(&list, TMP_MARK,
1836+
min_generation);
1837+
18321838
commit_list_insert(new_commit, &used);
18331839
if (new_commit == old_commit) {
18341840
found = 1;

sha1-name.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1211,7 +1211,8 @@ static int get_oid_oneline(const char *prefix, struct object_id *oid,
12111211
struct commit *commit;
12121212
int matches;
12131213

1214-
commit = pop_most_recent_commit(&list, ONELINE_SEEN);
1214+
commit = pop_most_recent_commit(&list, ONELINE_SEEN,
1215+
GENERATION_NUMBER_ZERO);
12151216
if (!parse_object(the_repository, &commit->object.oid))
12161217
continue;
12171218
buf = get_commit_buffer(commit, NULL);

walker.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ static int process_commit(struct walker *walker, struct commit *commit)
8282
return -1;
8383

8484
while (complete && complete->item->date >= commit->date) {
85-
pop_most_recent_commit(&complete, COMPLETE);
85+
pop_most_recent_commit(&complete, COMPLETE,
86+
GENERATION_NUMBER_ZERO);
8687
}
8788

8889
if (commit->object.flags & COMPLETE)

0 commit comments

Comments
 (0)