summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/prune.c2
-rw-r--r--builtin/repack.c6
-rw-r--r--commit.h4
-rw-r--r--shallow.c23
-rwxr-xr-xt/t5537-fetch-shallow.sh27
5 files changed, 54 insertions, 8 deletions
diff --git a/builtin/prune.c b/builtin/prune.c
index 4916a4daa2..b29ce4abbc 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -161,7 +161,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
free(s);
if (is_repository_shallow(the_repository))
- prune_shallow(show_only);
+ prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0);
return 0;
}
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)
diff --git a/commit.h b/commit.h
index 12b8b2d654..dc5107259f 100644
--- a/commit.h
+++ b/commit.h
@@ -256,7 +256,9 @@ extern void assign_shallow_commits_to_refs(struct shallow_info *info,
uint32_t **used,
int *ref_status);
extern int delayed_reachability_test(struct shallow_info *si, int c);
-extern void prune_shallow(int show_only);
+#define PRUNE_SHOW_ONLY 1
+#define PRUNE_QUICK 2
+extern void prune_shallow(unsigned options);
extern struct trace_key trace_shallow;
int is_descendant_of(struct commit *, struct commit_list *);
diff --git a/shallow.c b/shallow.c
index dbe8a2a290..c1b68533ca 100644
--- a/shallow.c
+++ b/shallow.c
@@ -246,6 +246,7 @@ static void check_shallow_file_for_update(struct repository *r)
#define SEEN_ONLY 1
#define VERBOSE 2
+#define QUICK 4
struct write_shallow_data {
struct strbuf *out;
@@ -260,7 +261,10 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
const char *hex = oid_to_hex(&graft->oid);
if (graft->nr_parent != -1)
return 0;
- if (data->flags & SEEN_ONLY) {
+ if (data->flags & QUICK) {
+ if (!has_object_file(&graft->oid))
+ return 0;
+ } else if (data->flags & SEEN_ONLY) {
struct commit *c = lookup_commit(the_repository, &graft->oid);
if (!c || !(c->object.flags & SEEN)) {
if (data->flags & VERBOSE)
@@ -370,16 +374,23 @@ void advertise_shallow_grafts(int fd)
/*
* mark_reachable_objects() should have been run prior to this and all
- * reachable commits marked as "SEEN".
+ * reachable commits marked as "SEEN", except when quick_prune is non-zero,
+ * in which case lines are excised from the shallow file if they refer to
+ * commits that do not exist (any longer).
*/
-void prune_shallow(int show_only)
+void prune_shallow(unsigned options)
{
struct lock_file shallow_lock = LOCK_INIT;
struct strbuf sb = STRBUF_INIT;
+ unsigned flags = SEEN_ONLY;
int fd;
- if (show_only) {
- write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY | VERBOSE);
+ if (options & PRUNE_QUICK)
+ flags |= QUICK;
+
+ if (options & PRUNE_SHOW_ONLY) {
+ flags |= VERBOSE;
+ write_shallow_commits_1(&sb, 0, NULL, flags);
strbuf_release(&sb);
return;
}
@@ -387,7 +398,7 @@ void prune_shallow(int show_only)
git_path_shallow(the_repository),
LOCK_DIE_ON_ERROR);
check_shallow_file_for_update(the_repository);
- if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
+ if (write_shallow_commits_1(&sb, 0, NULL, flags)) {
if (write_in_full(fd, sb.buf, sb.len) < 0)
die_errno("failed to write to %s",
get_lock_file_path(&shallow_lock));
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
index 7045685e2d..6faf17e17a 100755
--- a/t/t5537-fetch-shallow.sh
+++ b/t/t5537-fetch-shallow.sh
@@ -186,6 +186,33 @@ EOF
test_cmp expect actual
'
+test_expect_success '.git/shallow is edited by repack' '
+ git init shallow-server &&
+ test_commit -C shallow-server A &&
+ test_commit -C shallow-server B &&
+ git -C shallow-server checkout -b branch &&
+ test_commit -C shallow-server C &&
+ test_commit -C shallow-server E &&
+ test_commit -C shallow-server D &&
+ d="$(git -C shallow-server rev-parse --verify D^0)" &&
+ git -C shallow-server checkout master &&
+
+ git clone --depth=1 --no-tags --no-single-branch \
+ "file://$PWD/shallow-server" shallow-client &&
+
+ : now remove the branch and fetch with prune &&
+ git -C shallow-server branch -D branch &&
+ git -C shallow-client fetch --prune --depth=1 \
+ origin "+refs/heads/*:refs/remotes/origin/*" &&
+ git -C shallow-client repack -adfl &&
+ test_must_fail git -C shallow-client rev-parse --verify $d^0 &&
+ ! grep $d shallow-client/.git/shallow &&
+
+ git -C shallow-server branch branch-orig $d &&
+ git -C shallow-client fetch --prune --depth=2 \
+ origin "+refs/heads/*:refs/remotes/origin/*"
+'
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd