summaryrefslogtreecommitdiff
path: root/builtin/repack.c
diff options
context:
space:
mode:
authorLibravatar Johannes Schindelin <johannes.schindelin@gmx.de>2018-10-24 08:56:13 -0700
committerLibravatar Junio C Hamano <gitster@pobox.com>2018-10-25 12:59:27 +0900
commit5dcfbf564c0f10869e568af4e05421f63b44fbbf (patch)
tree3d3642cfb10a215184ed5aae848cb09e0c1437c4 /builtin/repack.c
parentshallow: offer to prune only non-existing entries (diff)
downloadtgif-5dcfbf564c0f10869e568af4e05421f63b44fbbf.tar.xz
repack -ad: prune the list of shallow commits
`git repack` can drop unreachable commits without further warning, making the corresponding entries in `.git/shallow` invalid, which causes serious problems when deepening the branches. One scenario where unreachable commits are dropped by `git repack` is when a `git fetch --prune` (or even a `git fetch` when a ref was force-pushed in the meantime) can make a commit unreachable that was reachable before. Therefore it is not safe to assume that a `git repack -adlf` will keep unreachable commits alone (under the assumption that they had not been packed in the first place, which is an assumption at least some of Git's code seems to make). This is particularly important to keep in mind when looking at the `.git/shallow` file: if any commits listed in that file become unreachable, it is not a problem, but if they go missing, it *is* a problem. One symptom of this problem is that a deepening fetch may now fail with fatal: error in object: unshallow <commit-hash> To avoid this problem, let's prune the shallow list in `git repack` when the `-d` option is passed, unless `-A` is passed, too (which would force the now-unreachable objects to be turned into loose objects instead of being deleted). Additionally, we also need to take `--keep-reachable` and `--unpack-unreachable=<date>` into account. Note: an alternative solution discussed during the review of this patch was to teach `git fetch` to simply ignore entries in .git/shallow if the corresponding commits do not exist locally. A quick test, however, revealed that the .git/shallow file is written during a shallow *clone*, in which case the commits do not exist, either, but the "shallow" line *does* need to be sent. Therefore, this approach would be a lot more finicky than the approach presented by the this patch. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin/repack.c')
-rw-r--r--builtin/repack.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/builtin/repack.c b/builtin/repack.c
index d5886039cc..3c30e16ec5 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -531,6 +531,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (!po_args.quiet && isatty(2))
opts |= PRUNE_PACKED_VERBOSE;
prune_packed_objects(opts);
+
+ if (!keep_unreachable &&
+ (!(pack_everything & LOOSEN_UNREACHABLE) ||
+ unpack_unreachable) &&
+ is_repository_shallow(the_repository))
+ prune_shallow(PRUNE_QUICK);
}
if (!no_update_server_info)