Teach construct_commit_graph() to walk all parents from the commits discovered in packfiles. This prevents gaps given by loose objects or previously-missed packfiles. Signed-off-by: Derrick Stolee <dstolee@xxxxxxxxxxxxx> --- commit-graph.c | 26 ++++++++++++++++++++++++++ t/t5318-commit-graph.sh | 14 ++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/commit-graph.c b/commit-graph.c index e5a1d9ee8b..cfa0415a21 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -5,6 +5,7 @@ #include "packfile.h" #include "commit.h" #include "object.h" +#include "revision.h" #include "commit-graph.h" #define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */ @@ -638,6 +639,29 @@ static int if_packed_commit_add_to_list(const struct object_id *oid, return 0; } +static void close_reachable(struct packed_oid_list *oids) +{ + int i; + struct rev_info revs; + struct commit *commit; + init_revisions(&revs, NULL); + + for (i = 0; i < oids->num; i++) { + commit = lookup_commit(oids->list[i]); + if (commit && !parse_commit(commit)) + revs.commits = commit_list_insert(commit, &revs.commits); + } + + if (prepare_revision_walk(&revs)) + die(_("revision walk setup failed")); + + while ((commit = get_revision(&revs)) != NULL) { + ALLOC_GROW(oids->list, oids->num + 1, oids->size); + oids->list[oids->num] = &(commit->object.oid); + (oids->num)++; + } +} + struct object_id *construct_commit_graph(const char *pack_dir, char **pack_indexes, int nr_packs) @@ -696,6 +720,8 @@ struct object_id *construct_commit_graph(const char *pack_dir, } else { for_each_packed_object(if_packed_commit_add_to_list, &oids, 0); } + + close_reachable(&oids); QSORT(oids.list, oids.num, commit_compare); count_distinct = 1; diff --git a/t/t5318-commit-graph.sh b/t/t5318-commit-graph.sh index b9a73f398c..2001b0b5b5 100755 --- a/t/t5318-commit-graph.sh +++ b/t/t5318-commit-graph.sh @@ -213,6 +213,20 @@ test_expect_success 'clear graph' \ _graph_git_behavior commits/20 merge/1 _graph_git_behavior commits/20 merge/2 +test_expect_success 'build graph from latest pack with closure' \ + 'graph5=$(cat new-idx | git commit-graph --write --update-head --stdin-packs) && + test_path_is_file ${packdir}/graph-${graph5}.graph && + test_path_is_file ${packdir}/graph-${graph1}.graph && + test_path_is_file ${packdir}/graph-head && + echo ${graph5} >expect && + cmp -n 40 expect ${packdir}/graph-head && + git commit-graph --read --graph-hash=${graph5} >output && + _graph_read_expect "21" "${packdir}" && + cmp expect output' + +_graph_git_behavior commits/20 merge/1 +_graph_git_behavior commits/20 merge/2 + test_expect_success 'setup bare repo' \ 'cd .. && git clone --bare full bare && -- 2.16.0.15.g9c3cf44.dirty