commit-graph: add --split option to builtin

Add a new "--split" option to the 'git commit-graph write' subcommand. This option allows the optional behavior of writing a commit-graph chain. The current behavior will add a tip commit-graph containing any commits that are not in the existing commit-graph or commit-graph chain. Later changes will allow merging the chain and expiring out-dated files. Add a new test script (t5324-split-commit-graph.sh) that demonstrates this behavior. Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Jun 18, 2019 at 11:14 UTC 135a7123755bfdde05da18012bebd2776f82b26c
3 files changed +138 -8
builtin/commit-graph.c
+7 -3
@@ -10,7 +10,7 @@ static char const * const builtin_commit_graph_usage[] = {
10 N_("git commit-graph [--object-dir <objdir>]"),
11 N_("git commit-graph read [--object-dir <objdir>]"),
12 N_("git commit-graph verify [--object-dir <objdir>]"),
13 - N_("git commit-graph write [--object-dir <objdir>] [--append] [--reachable|--stdin-packs|--stdin-commits]"),
13 + N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits]"),
14 NULL
15 };
16
@@ -25,7 +25,7 @@ static const char * const builtin_commit_graph_read_usage[] = {
25 };
26
27 static const char * const builtin_commit_graph_write_usage[] = {
28 - N_("git commit-graph write [--object-dir <objdir>] [--append] [--reachable|--stdin-packs|--stdin-commits]"),
28 + N_("git commit-graph write [--object-dir <objdir>] [--append|--split] [--reachable|--stdin-packs|--stdin-commits]"),
29 NULL
30 };
31
@@ -35,9 +35,9 @@ static struct opts_commit_graph {
35 int stdin_packs;
36 int stdin_commits;
37 int append;
38 + int split;
39 } opts;
40
40 -
41 static int graph_verify(int argc, const char **argv)
42 {
43 struct commit_graph *graph = NULL;
@@ -156,6 +156,8 @@ static int graph_write(int argc, const char **argv)
156 N_("start walk at commits listed by stdin")),
157 OPT_BOOL(0, "append", &opts.append,
158 N_("include all commits already in the commit-graph file")),
159 + OPT_BOOL(0, "split", &opts.split,
160 + N_("allow writing an incremental commit-graph file")),
161 OPT_END(),
162 };
163
@@ -169,6 +171,8 @@ static int graph_write(int argc, const char **argv)
171 opts.obj_dir = get_object_directory();
172 if (opts.append)
173 flags |= COMMIT_GRAPH_APPEND;
174 + if (opts.split)
175 + flags |= COMMIT_GRAPH_SPLIT;
176
177 read_replace_refs = 0;
178
commit-graph.c
+9 -5
@@ -1472,12 +1472,16 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
1472 }
1473
1474 if (ctx->base_graph_name) {
1475 - result = rename(ctx->base_graph_name,
1476 - ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2]);
1475 + const char *dest = ctx->commit_graph_filenames_after[
1476 + ctx->num_commit_graphs_after - 2];
1477
1478 - if (result) {
1479 - error(_("failed to rename base commit-graph file"));
1480 - return -1;
1478 + if (strcmp(ctx->base_graph_name, dest)) {
1479 + result = rename(ctx->base_graph_name, dest);
1480 +
1481 + if (result) {
1482 + error(_("failed to rename base commit-graph file"));
1483 + return -1;
1484 + }
1485 }
1486 } else {
1487 char *graph_name = get_commit_graph_filename(ctx->obj_dir);
t/t5324-split-commit-graph.sh new
+122
@@ -0,0 +1,122 @@
1 +#!/bin/sh
2 +
3 +test_description='split commit graph'
4 +. ./test-lib.sh
5 +
6 +GIT_TEST_COMMIT_GRAPH=0
7 +
8 +test_expect_success 'setup repo' '
9 + git init &&
10 + git config core.commitGraph true &&
11 + infodir=".git/objects/info" &&
12 + graphdir="$infodir/commit-graphs" &&
13 + test_oid_init
14 +'
15 +
16 +graph_read_expect() {
17 + NUM_BASE=0
18 + if test ! -z $2
19 + then
20 + NUM_BASE=$2
21 + fi
22 + cat >expect <<- EOF
23 + header: 43475048 1 1 3 $NUM_BASE
24 + num_commits: $1
25 + chunks: oid_fanout oid_lookup commit_metadata
26 + EOF
27 + git commit-graph read >output &&
28 + test_cmp expect output
29 +}
30 +
31 +test_expect_success 'create commits and write commit-graph' '
32 + for i in $(test_seq 3)
33 + do
34 + test_commit $i &&
35 + git branch commits/$i || return 1
36 + done &&
37 + git commit-graph write --reachable &&
38 + test_path_is_file $infodir/commit-graph &&
39 + graph_read_expect 3
40 +'
41 +
42 +graph_git_two_modes() {
43 + git -c core.commitGraph=true $1 >output
44 + git -c core.commitGraph=false $1 >expect
45 + test_cmp expect output
46 +}
47 +
48 +graph_git_behavior() {
49 + MSG=$1
50 + BRANCH=$2
51 + COMPARE=$3
52 + test_expect_success "check normal git operations: $MSG" '
53 + graph_git_two_modes "log --oneline $BRANCH" &&
54 + graph_git_two_modes "log --topo-order $BRANCH" &&
55 + graph_git_two_modes "log --graph $COMPARE..$BRANCH" &&
56 + graph_git_two_modes "branch -vv" &&
57 + graph_git_two_modes "merge-base -a $BRANCH $COMPARE"
58 + '
59 +}
60 +
61 +graph_git_behavior 'graph exists' commits/3 commits/1
62 +
63 +verify_chain_files_exist() {
64 + for hash in $(cat $1/commit-graph-chain)
65 + do
66 + test_path_is_file $1/graph-$hash.graph || return 1
67 + done
68 +}
69 +
70 +test_expect_success 'add more commits, and write a new base graph' '
71 + git reset --hard commits/1 &&
72 + for i in $(test_seq 4 5)
73 + do
74 + test_commit $i &&
75 + git branch commits/$i || return 1
76 + done &&
77 + git reset --hard commits/2 &&
78 + for i in $(test_seq 6 10)
79 + do
80 + test_commit $i &&
81 + git branch commits/$i || return 1
82 + done &&
83 + git reset --hard commits/2 &&
84 + git merge commits/4 &&
85 + git branch merge/1 &&
86 + git reset --hard commits/4 &&
87 + git merge commits/6 &&
88 + git branch merge/2 &&
89 + git commit-graph write --reachable &&
90 + graph_read_expect 12
91 +'
92 +
93 +test_expect_success 'add three more commits, write a tip graph' '
94 + git reset --hard commits/3 &&
95 + git merge merge/1 &&
96 + git merge commits/5 &&
97 + git merge merge/2 &&
98 + git branch merge/3 &&
99 + git commit-graph write --reachable --split &&
100 + test_path_is_missing $infodir/commit-graph &&
101 + test_path_is_file $graphdir/commit-graph-chain &&
102 + ls $graphdir/graph-*.graph >graph-files &&
103 + test_line_count = 2 graph-files &&
104 + verify_chain_files_exist $graphdir
105 +'
106 +
107 +graph_git_behavior 'split commit-graph: merge 3 vs 2' merge/3 merge/2
108 +
109 +test_expect_success 'add one commit, write a tip graph' '
110 + test_commit 11 &&
111 + git branch commits/11 &&
112 + git commit-graph write --reachable --split &&
113 + test_path_is_missing $infodir/commit-graph &&
114 + test_path_is_file $graphdir/commit-graph-chain &&
115 + ls $graphdir/graph-*.graph >graph-files &&
116 + test_line_count = 3 graph-files &&
117 + verify_chain_files_exist $graphdir
118 +'
119 +
120 +graph_git_behavior 'three-layer commit-graph: commit 11 vs 6' commits/11 commits/6
121 +
122 +test_done