Skip to content

Commit

Permalink
commit: add generation to pop_most_recent_commit()
Browse files Browse the repository at this point in the history
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 <dstolee@microsoft.com>
  • Loading branch information
derrickstolee authored and dscho committed Jul 5, 2018
1 parent dda4905 commit 7f0582a
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 8 deletions.
7 changes: 5 additions & 2 deletions commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,8 @@ void commit_list_sort_by_date(struct commit_list **list)
}

struct commit *pop_most_recent_commit(struct commit_list **list,
unsigned int mark)
unsigned int mark,
uint32_t min_generation)
{
struct commit *ret = pop_commit(list);
struct commit_list *parents = ret->parents;
Expand All @@ -546,7 +547,9 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
struct commit *commit = parents->item;
if (!parse_commit(commit) && !(commit->object.flags & mark)) {
commit->object.flags |= mark;
commit_list_insert_by_date(commit, list);

if (commit->generation >= min_generation)
commit_list_insert_by_date(commit, list);
}
parents = parents->next;
}
Expand Down
6 changes: 5 additions & 1 deletion commit.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,13 @@ extern const char *skip_blank_lines(const char *msg);

/** Removes the first commit from a list sorted by date, and adds all
* of its parents.
*
* The parents are not added if their generation number is strictly
* lower than min_generation.
**/
struct commit *pop_most_recent_commit(struct commit_list **list,
unsigned int mark);
unsigned int mark,
uint32_t min_generation);

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

Expand Down
3 changes: 2 additions & 1 deletion fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,8 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
while (complete && cutoff <= complete->item->date) {
print_verbose(args, _("Marking %s as complete"),
oid_to_hex(&complete->item->object.oid));
pop_most_recent_commit(&complete, COMPLETE);
pop_most_recent_commit(&complete, COMPLETE,
GENERATION_NUMBER_ZERO);
}
}

Expand Down
10 changes: 8 additions & 2 deletions remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -1795,6 +1795,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
struct commit *old_commit, *new_commit;
struct commit_list *list, *used;
int found = 0;
uint32_t min_generation;

/*
* Both new_commit and old_commit must be commit-ish and new_commit is descendant of
Expand All @@ -1810,13 +1811,18 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
return 0;
new_commit = (struct commit *) o;

if (parse_commit(new_commit) < 0)
if (parse_commit(new_commit) < 0 ||
parse_commit(old_commit) < 0)
return 0;

min_generation = old_commit->generation;

used = list = NULL;
commit_list_insert(new_commit, &list);
while (list) {
new_commit = pop_most_recent_commit(&list, TMP_MARK);
new_commit = pop_most_recent_commit(&list, TMP_MARK,
min_generation);

commit_list_insert(new_commit, &used);
if (new_commit == old_commit) {
found = 1;
Expand Down
3 changes: 2 additions & 1 deletion sha1-name.c
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,8 @@ static int get_oid_oneline(const char *prefix, struct object_id *oid,
struct commit *commit;
int matches;

commit = pop_most_recent_commit(&list, ONELINE_SEEN);
commit = pop_most_recent_commit(&list, ONELINE_SEEN,
GENERATION_NUMBER_ZERO);
if (!parse_object(&commit->object.oid))
continue;
buf = get_commit_buffer(commit, NULL);
Expand Down
3 changes: 2 additions & 1 deletion walker.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ static int process_commit(struct walker *walker, struct commit *commit)
return -1;

while (complete && complete->item->date >= commit->date) {
pop_most_recent_commit(&complete, COMPLETE);
pop_most_recent_commit(&complete, COMPLETE,
GENERATION_NUMBER_ZERO);
}

if (commit->object.flags & COMPLETE)
Expand Down

0 comments on commit 7f0582a

Please sign in to comment.