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
This commit is contained in:
Junio C Hamano 2018-11-06 15:50:18 +09:00
commit ea100b6dcb
5 changed files with 54 additions and 8 deletions

View File

@ -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;
}

View File

@ -550,6 +550,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)

View File

@ -251,7 +251,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;
extern int interactive_add(int argc, const char **argv, const char *prefix, int patch);

View File

@ -247,6 +247,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;
@ -261,7 +262,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)
@ -371,16 +375,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;
}
@ -388,7 +399,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));

View File

@ -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