commit-graph: normalize commit-graph filenames

When writing commit-graph files, we append path data to an object directory, which may be specified by the user via the '--object-dir' option. If the user supplies a trailing slash, or some other alternative path format, the resulting path may be usable for writing to the correct location. However, when expiring graph files from the <obj-dir>/info/commit-graphs directory during a write, we need to compare paths with exact string matches. Normalize the commit-graph filenames to avoid ambiguity. This creates extra allocations, but this is a constant multiple of the number of commit-graph files, which should be a number in the single digits. Further normalize the object directory in the context. Due to a comparison between g->obj_dir and ctx->obj_dir in split_graph_merge_strategy(), a trailing slash would prevent any merging of layers within the same object directory. The check is there to ensure we do not merge across alternates. Update the tests to include a case with this trailing slash problem. 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 16110c9348fc2022e78f2581968cf428c056dc5b
2 files changed +29 -8
commit-graph.c
+23 -7
@@ -43,15 +43,23 @@
43
44 char *get_commit_graph_filename(const char *obj_dir)
45 {
46 - return xstrfmt("%s/info/commit-graph", obj_dir);
46 + char *filename = xstrfmt("%s/info/commit-graph", obj_dir);
47 + char *normalized = xmalloc(strlen(filename) + 1);
48 + normalize_path_copy(normalized, filename);
49 + free(filename);
50 + return normalized;
51 }
52
53 static char *get_split_graph_filename(const char *obj_dir,
54 const char *oid_hex)
55 {
52 - return xstrfmt("%s/info/commit-graphs/graph-%s.graph",
53 - obj_dir,
54 - oid_hex);
56 + char *filename = xstrfmt("%s/info/commit-graphs/graph-%s.graph",
57 + obj_dir,
58 + oid_hex);
59 + char *normalized = xmalloc(strlen(filename) + 1);
60 + normalize_path_copy(normalized, filename);
61 + free(filename);
62 + return normalized;
63 }
64
65 static char *get_chain_filename(const char *obj_dir)
@@ -746,7 +754,7 @@ struct packed_oid_list {
754
755 struct write_commit_graph_context {
756 struct repository *r;
749 - const char *obj_dir;
757 + char *obj_dir;
758 char *graph_name;
759 struct packed_oid_list oids;
760 struct packed_commit_list commits;
@@ -1729,7 +1737,6 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
1737
1738 if (!found)
1739 unlink(path.buf);
1732 -
1740 }
1741 }
1742
@@ -1741,6 +1748,7 @@ int write_commit_graph(const char *obj_dir,
1748 {
1749 struct write_commit_graph_context *ctx;
1750 uint32_t i, count_distinct = 0;
1751 + size_t len;
1752 int res = 0;
1753
1754 if (!commit_graph_compatible(the_repository))
@@ -1748,7 +1756,14 @@ int write_commit_graph(const char *obj_dir,
1756
1757 ctx = xcalloc(1, sizeof(struct write_commit_graph_context));
1758 ctx->r = the_repository;
1751 - ctx->obj_dir = obj_dir;
1759 +
1760 + /* normalize object dir with no trailing slash */
1761 + ctx->obj_dir = xmallocz(strlen(obj_dir) + 1);
1762 + normalize_path_copy(ctx->obj_dir, obj_dir);
1763 + len = strlen(ctx->obj_dir);
1764 + if (len && ctx->obj_dir[len - 1] == '/')
1765 + ctx->obj_dir[len - 1] = 0;
1766 +
1767 ctx->append = flags & COMMIT_GRAPH_APPEND ? 1 : 0;
1768 ctx->report_progress = flags & COMMIT_GRAPH_PROGRESS ? 1 : 0;
1769 ctx->split = flags & COMMIT_GRAPH_SPLIT ? 1 : 0;
@@ -1856,6 +1871,7 @@ cleanup:
1871 free(ctx->graph_name);
1872 free(ctx->commits.list);
1873 free(ctx->oids.list);
1874 + free(ctx->obj_dir);
1875
1876 if (ctx->commit_graph_filenames_after) {
1877 for (i = 0; i < ctx->num_commit_graphs_after; i++) {
t/t5324-split-commit-graph.sh
+6 -1
@@ -163,7 +163,12 @@ test_expect_success 'create fork and chain across alternate' '
163 test_line_count = 1 graph-files &&
164 git -c core.commitGraph=true rev-list HEAD >expect &&
165 git -c core.commitGraph=false rev-list HEAD >actual &&
166 - test_cmp expect actual
166 + test_cmp expect actual &&
167 + test_commit 14 &&
168 + git commit-graph write --reachable --split --object-dir=.git/objects/ &&
169 + test_line_count = 3 $graphdir/commit-graph-chain &&
170 + ls $graphdir/graph-*.graph >graph-files &&
171 + test_line_count = 1 graph-files
172 )
173 '
174