Skip to content

Commit ea100b6

Browse files
committed
Merge branch 'js/shallow-and-fetch-prune'
"git repack" in a shallow clone did not correctly update the shallow points in the repository, leading to a repository that does not pass fsck. * js/shallow-and-fetch-prune: repack -ad: prune the list of shallow commits shallow: offer to prune only non-existing entries repack: point out a bug handling stale shallow info
2 parents a5ab66e + 5dcfbf5 commit ea100b6

File tree

5 files changed

+54
-8
lines changed

5 files changed

+54
-8
lines changed

builtin/prune.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
161161
free(s);
162162

163163
if (is_repository_shallow(the_repository))
164-
prune_shallow(show_only);
164+
prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0);
165165

166166
return 0;
167167
}

builtin/repack.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,12 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
550550
if (!po_args.quiet && isatty(2))
551551
opts |= PRUNE_PACKED_VERBOSE;
552552
prune_packed_objects(opts);
553+
554+
if (!keep_unreachable &&
555+
(!(pack_everything & LOOSEN_UNREACHABLE) ||
556+
unpack_unreachable) &&
557+
is_repository_shallow(the_repository))
558+
prune_shallow(PRUNE_QUICK);
553559
}
554560

555561
if (!no_update_server_info)

commit.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,9 @@ extern void assign_shallow_commits_to_refs(struct shallow_info *info,
251251
uint32_t **used,
252252
int *ref_status);
253253
extern int delayed_reachability_test(struct shallow_info *si, int c);
254-
extern void prune_shallow(int show_only);
254+
#define PRUNE_SHOW_ONLY 1
255+
#define PRUNE_QUICK 2
256+
extern void prune_shallow(unsigned options);
255257
extern struct trace_key trace_shallow;
256258

257259
extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);

shallow.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ static void check_shallow_file_for_update(struct repository *r)
247247

248248
#define SEEN_ONLY 1
249249
#define VERBOSE 2
250+
#define QUICK 4
250251

251252
struct write_shallow_data {
252253
struct strbuf *out;
@@ -261,7 +262,10 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
261262
const char *hex = oid_to_hex(&graft->oid);
262263
if (graft->nr_parent != -1)
263264
return 0;
264-
if (data->flags & SEEN_ONLY) {
265+
if (data->flags & QUICK) {
266+
if (!has_object_file(&graft->oid))
267+
return 0;
268+
} else if (data->flags & SEEN_ONLY) {
265269
struct commit *c = lookup_commit(the_repository, &graft->oid);
266270
if (!c || !(c->object.flags & SEEN)) {
267271
if (data->flags & VERBOSE)
@@ -371,24 +375,31 @@ void advertise_shallow_grafts(int fd)
371375

372376
/*
373377
* mark_reachable_objects() should have been run prior to this and all
374-
* reachable commits marked as "SEEN".
378+
* reachable commits marked as "SEEN", except when quick_prune is non-zero,
379+
* in which case lines are excised from the shallow file if they refer to
380+
* commits that do not exist (any longer).
375381
*/
376-
void prune_shallow(int show_only)
382+
void prune_shallow(unsigned options)
377383
{
378384
struct lock_file shallow_lock = LOCK_INIT;
379385
struct strbuf sb = STRBUF_INIT;
386+
unsigned flags = SEEN_ONLY;
380387
int fd;
381388

382-
if (show_only) {
383-
write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY | VERBOSE);
389+
if (options & PRUNE_QUICK)
390+
flags |= QUICK;
391+
392+
if (options & PRUNE_SHOW_ONLY) {
393+
flags |= VERBOSE;
394+
write_shallow_commits_1(&sb, 0, NULL, flags);
384395
strbuf_release(&sb);
385396
return;
386397
}
387398
fd = hold_lock_file_for_update(&shallow_lock,
388399
git_path_shallow(the_repository),
389400
LOCK_DIE_ON_ERROR);
390401
check_shallow_file_for_update(the_repository);
391-
if (write_shallow_commits_1(&sb, 0, NULL, SEEN_ONLY)) {
402+
if (write_shallow_commits_1(&sb, 0, NULL, flags)) {
392403
if (write_in_full(fd, sb.buf, sb.len) < 0)
393404
die_errno("failed to write to %s",
394405
get_lock_file_path(&shallow_lock));

t/t5537-fetch-shallow.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,33 @@ EOF
186186
test_cmp expect actual
187187
'
188188

189+
test_expect_success '.git/shallow is edited by repack' '
190+
git init shallow-server &&
191+
test_commit -C shallow-server A &&
192+
test_commit -C shallow-server B &&
193+
git -C shallow-server checkout -b branch &&
194+
test_commit -C shallow-server C &&
195+
test_commit -C shallow-server E &&
196+
test_commit -C shallow-server D &&
197+
d="$(git -C shallow-server rev-parse --verify D^0)" &&
198+
git -C shallow-server checkout master &&
199+
200+
git clone --depth=1 --no-tags --no-single-branch \
201+
"file://$PWD/shallow-server" shallow-client &&
202+
203+
: now remove the branch and fetch with prune &&
204+
git -C shallow-server branch -D branch &&
205+
git -C shallow-client fetch --prune --depth=1 \
206+
origin "+refs/heads/*:refs/remotes/origin/*" &&
207+
git -C shallow-client repack -adfl &&
208+
test_must_fail git -C shallow-client rev-parse --verify $d^0 &&
209+
! grep $d shallow-client/.git/shallow &&
210+
211+
git -C shallow-server branch branch-orig $d &&
212+
git -C shallow-client fetch --prune --depth=2 \
213+
origin "+refs/heads/*:refs/remotes/origin/*"
214+
'
215+
189216
. "$TEST_DIRECTORY"/lib-httpd.sh
190217
start_httpd
191218

0 commit comments

Comments
 (0)