shallow: reset commit grafts when shallow is reset

When reset_repository_shallow() is called, Git clears its cache of shallow information, so that if shallow information is re-requested, Git will read fresh data from disk instead of reusing its stale cached data. However, the cache of commit grafts is not likewise cleared, even though there are commit grafts created from shallow information. This means that if on-disk shallow information were to be updated and then a commit-graft-using codepath were run (for example, a revision walk), Git would be using stale commit graft information. This can be seen from the test in this patch, in which Git performs a revision walk (to check for changed submodules) after a fetch with --update-shallow. Therefore, clear the cache of commit grafts whenever reset_repository_shallow() is called. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Mar 17, 2022 at 11:24 UTC 2a69ff09d5654de31361365e3faf9f8495f03ed7
5 files changed +22
commit.c
+10
@@ -249,6 +249,16 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
249 return ret;
250 }
251
252 +void reset_commit_grafts(struct repository *r)
253 +{
254 + int i;
255 +
256 + for (i = 0; i < r->parsed_objects->grafts_nr; i++)
257 + free(r->parsed_objects->grafts[i]);
258 + r->parsed_objects->grafts_nr = 0;
259 + r->parsed_objects->commit_graft_prepared = 0;
260 +}
261 +
262 struct commit_buffer {
263 void *buffer;
264 unsigned long size;
commit.h
+1
@@ -249,6 +249,7 @@ int commit_graft_pos(struct repository *r, const struct object_id *oid);
249 int register_commit_graft(struct repository *r, struct commit_graft *, int);
250 void prepare_commit_graft(struct repository *r);
251 struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
252 +void reset_commit_grafts(struct repository *r);
253
254 struct commit *get_fork_point(const char *refname, struct commit *commit);
255
shallow.c
+1
@@ -90,6 +90,7 @@ static void reset_repository_shallow(struct repository *r)
90 {
91 r->parsed_objects->is_shallow = -1;
92 stat_validity_clear(r->parsed_objects->shallow_stat);
93 + reset_commit_grafts(r);
94 }
95
96 int commit_shallow_file(struct repository *r, struct shallow_lock *lk)
submodule.c
+1
@@ -22,6 +22,7 @@
22 #include "parse-options.h"
23 #include "object-store.h"
24 #include "commit-reach.h"
25 +#include "shallow.h"
26
27 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
28 static int initialized_fetch_ref_tips;
t/t5537-fetch-shallow.sh
+9
@@ -161,6 +161,15 @@ test_expect_success 'fetch --update-shallow' '
161 )
162 '
163
164 +test_expect_success 'fetch --update-shallow into a repo with submodules' '
165 + git init a-submodule &&
166 + test_commit -C a-submodule foo &&
167 + git init repo-with-sub &&
168 + git -C repo-with-sub submodule add ../a-submodule a-submodule &&
169 + git -C repo-with-sub commit -m "added submodule" &&
170 + git -C repo-with-sub fetch --update-shallow ../shallow/.git refs/heads/*:refs/remotes/shallow/*
171 +'
172 +
173 test_expect_success 'fetch --update-shallow (with fetch.writeCommitGraph)' '
174 (
175 cd shallow &&