Skip to content

Commit ce16364

Browse files
ttaylorrgitster
authored andcommitted
commit.c: don't persist substituted parents when unshallowing
Since 37b9dca (shallow.c: use '{commit,rollback}_shallow_file', 2020-04-22), Git knows how to reset stat-validity checks for the $GIT_DIR/shallow file, allowing it to change between a shallow and non-shallow state in the same process (e.g., in the case of 'git fetch --unshallow'). However, when $GIT_DIR/shallow changes, Git does not alter or remove any grafts (nor substituted parents) in memory. This comes up in a "git fetch --unshallow" with fetch.writeCommitGraph set to true. Ordinarily in a shallow repository (and before 37b9dca, even in this case), commit_graph_compatible() would return false, indicating that the repository should not be used to write a commit-graphs (since commit-graph files cannot represent a shallow history). But since 37b9dca, in an --unshallow operation that check succeeds. Thus even though the repository isn't shallow any longer (that is, we have all of the objects), the in-core representation of those objects still has munged parents at the shallow boundaries. When the commit-graph write proceeds, we use the incorrect parentage, producing wrong results. There are two ways for a user to work around this: either (1) set 'fetch.writeCommitGraph' to 'false', or (2) drop the commit-graph after unshallowing. One way to fix this would be to reset the parsed object pool entirely (flushing the cache and thus preventing subsequent reads from modifying their parents) after unshallowing. That would produce a problem when callers have a now-stale reference to the old pool, and so this patch implements a different approach. Instead, attach a new bit to the pool, 'substituted_parent', which indicates if the repository *ever* stored a commit which had its parents modified (i.e., the shallow boundary prior to unshallowing). This bit needs to be sticky because all reads subsequent to modifying a commit's parents are unreliable when unshallowing. Modify the check in 'commit_graph_compatible' to take this bit into account, and correctly avoid generating commit-graphs in this case, thus solving the bug. Helped-by: Derrick Stolee <[email protected]> Helped-by: Jonathan Nieder <[email protected]> Reported-by: Jay Conrod <[email protected]> Reviewed-by: Jonathan Nieder <[email protected]> Signed-off-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 37b9dca commit ce16364

File tree

4 files changed

+19
-1
lines changed

4 files changed

+19
-1
lines changed

commit-graph.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ static int commit_graph_compatible(struct repository *r)
8888
}
8989

9090
prepare_commit_graft(r);
91-
if (r->parsed_objects && r->parsed_objects->grafts_nr)
91+
if (r->parsed_objects &&
92+
(r->parsed_objects->grafts_nr || r->parsed_objects->substituted_parent))
9293
return 0;
9394
if (is_repository_shallow(r))
9495
return 0;

commit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,8 @@ int parse_commit_buffer(struct repository *r, struct commit *item, const void *b
435435
pptr = &item->parents;
436436

437437
graft = lookup_commit_graft(r, &item->object.oid);
438+
if (graft)
439+
r->parsed_objects->substituted_parent = 1;
438440
while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
439441
struct commit *new_parent;
440442

object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct parsed_object_pool {
2626
char *alternate_shallow_file;
2727

2828
int commit_graft_prepared;
29+
int substituted_parent;
2930

3031
struct buffer_slab *buffer_slab;
3132
};

t/t5537-fetch-shallow.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,20 @@ test_expect_success 'fetch --unshallow from shallow clone' '
8181
)
8282
'
8383

84+
test_expect_success 'fetch --unshallow from a full clone' '
85+
git clone --no-local --depth=2 .git shallow3 &&
86+
(
87+
cd shallow3 &&
88+
git log --format=%s >actual &&
89+
test_write_lines 4 3 >expect &&
90+
test_cmp expect actual &&
91+
git -c fetch.writeCommitGraph fetch --unshallow &&
92+
git log origin/master --format=%s >actual &&
93+
test_write_lines 4 3 2 1 >expect &&
94+
test_cmp expect actual
95+
)
96+
'
97+
8498
test_expect_success 'fetch something upstream has but hidden by clients shallow boundaries' '
8599
# the blob "1" is available in .git but hidden by the
86100
# shallow2/.git/shallow and it should be resent

0 commit comments

Comments
 (0)