summaryrefslogtreecommitdiff
path: root/t/t1460-refs-migrate.sh
diff options
context:
space:
mode:
Diffstat (limited to 't/t1460-refs-migrate.sh')
-rwxr-xr-xt/t1460-refs-migrate.sh320
1 files changed, 320 insertions, 0 deletions
diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh
new file mode 100755
index 0000000000..2ab97e1b7d
--- /dev/null
+++ b/t/t1460-refs-migrate.sh
@@ -0,0 +1,320 @@
+#!/bin/sh
+
+test_description='migration of ref storage backends'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Migrate the provided repository from one format to the other and
+# verify that the references and logs are migrated over correctly.
+# Usage: test_migration <repo> <format> [<skip_reflog_verify> [<options...>]]
+# <repo> is the relative path to the repo to be migrated.
+# <format> is the ref format to be migrated to.
+# <skip_reflog_verify> (default: false) whether to skip reflog verification.
+# <options...> are other options be passed directly to 'git refs migrate'.
+test_migration () {
+ repo=$1 &&
+ format=$2 &&
+ shift 2 &&
+ skip_reflog_verify=false &&
+ if test $# -ge 1
+ then
+ skip_reflog_verify=$1
+ shift
+ fi &&
+ git -C "$repo" for-each-ref --include-root-refs \
+ --format='%(refname) %(objectname) %(symref)' >expect &&
+ if ! $skip_reflog_verify
+ then
+ git -C "$repo" reflog --all >expect_logs &&
+ git -C "$repo" reflog list >expect_log_list
+ fi &&
+
+ git -C "$repo" refs migrate --ref-format="$format" "$@" &&
+
+ git -C "$repo" for-each-ref --include-root-refs \
+ --format='%(refname) %(objectname) %(symref)' >actual &&
+ test_cmp expect actual &&
+ if ! $skip_reflog_verify
+ then
+ git -C "$repo" reflog --all >actual_logs &&
+ git -C "$repo" reflog list >actual_log_list &&
+ test_cmp expect_logs actual_logs &&
+ test_cmp expect_log_list actual_log_list
+ fi &&
+
+ git -C "$repo" rev-parse --show-ref-format >actual &&
+ echo "$format" >expect &&
+ test_cmp expect actual
+}
+
+test_expect_success 'setup' '
+ rm -rf .git
+'
+
+test_expect_success "superfluous arguments" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_must_fail git -C repo refs migrate foo 2>err &&
+ cat >expect <<-EOF &&
+ usage: too many arguments
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success "missing ref storage format" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_must_fail git -C repo refs migrate 2>err &&
+ cat >expect <<-EOF &&
+ usage: missing --ref-format=<format>
+ EOF
+ test_cmp expect err
+'
+
+test_expect_success "unknown ref storage format" '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_must_fail git -C repo refs migrate \
+ --ref-format=unknown 2>err &&
+ cat >expect <<-EOF &&
+ error: unknown ref storage format ${SQ}unknown${SQ}
+ EOF
+ test_cmp expect err
+'
+
+ref_formats="files reftable"
+for from_format in $ref_formats
+do
+ for to_format in $ref_formats
+ do
+ if test "$from_format" = "$to_format"
+ then
+ continue
+ fi
+
+ test_expect_success "$from_format: migration to same format fails" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_must_fail git -C repo refs migrate \
+ --ref-format=$from_format 2>err &&
+ cat >expect <<-EOF &&
+ error: repository already uses ${SQ}$from_format${SQ} format
+ EOF
+ test_cmp expect err
+ '
+
+ test_expect_success "$from_format -> $to_format: migration with worktree fails" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ git -C repo worktree add wt &&
+ test_must_fail git -C repo refs migrate \
+ --ref-format=$to_format 2>err &&
+ cat >expect <<-EOF &&
+ error: migrating repositories with worktrees is not supported yet
+ EOF
+ test_cmp expect err
+ '
+
+ test_expect_success "$from_format -> $to_format: unborn HEAD" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: single ref" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: bare repository" '
+ test_when_finished "rm -rf repo repo.git" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git clone --ref-format=$from_format --mirror repo repo.git &&
+ test_migration repo.git "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: dangling symref" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo symbolic-ref BROKEN_HEAD refs/heads/nonexistent &&
+ test_migration repo "$to_format" &&
+ echo refs/heads/nonexistent >expect &&
+ git -C repo symbolic-ref BROKEN_HEAD >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$from_format -> $to_format: broken ref" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ test-tool -C repo ref-store main update-ref "" refs/heads/broken \
+ "$(test_oid 001)" "$ZERO_OID" REF_SKIP_CREATE_REFLOG,REF_SKIP_OID_VERIFICATION &&
+ test_migration repo "$to_format" true &&
+ test_oid 001 >expect &&
+ git -C repo rev-parse refs/heads/broken >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$from_format -> $to_format: pseudo-refs" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo update-ref FOO_HEAD HEAD &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: special refs are left alone" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo rev-parse HEAD >repo/.git/MERGE_HEAD &&
+ git -C repo rev-parse MERGE_HEAD &&
+ test_migration repo "$to_format" &&
+ test_path_is_file repo/.git/MERGE_HEAD
+ '
+
+ test_expect_success "$from_format -> $to_format: a bunch of refs" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+
+ test_commit -C repo initial &&
+ cat >input <<-EOF &&
+ create FOO_HEAD HEAD
+ create refs/heads/branch-1 HEAD
+ create refs/heads/branch-2 HEAD
+ create refs/heads/branch-3 HEAD
+ create refs/heads/branch-4 HEAD
+ create refs/tags/tag-1 HEAD
+ create refs/tags/tag-2 HEAD
+ EOF
+ git -C repo update-ref --stdin <input &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: dry-run migration does not modify repository" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo refs migrate --dry-run \
+ --ref-format=$to_format >output &&
+ grep "Finished dry-run migration of refs" output &&
+ test_path_is_dir repo/.git/ref_migration.* &&
+ echo $from_format >expect &&
+ git -C repo rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+ '
+
+ test_expect_success "$from_format -> $to_format: reflogs of symrefs with target deleted" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ git -C repo branch branch-1 HEAD &&
+ git -C repo symbolic-ref refs/heads/symref refs/heads/branch-1 &&
+ cat >input <<-EOF &&
+ delete refs/heads/branch-1
+ EOF
+ git -C repo update-ref --stdin <input &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: reflogs order is retained" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit --date "100005000 +0700" --no-tag -C repo initial &&
+ test_commit --date "100003000 +0700" --no-tag -C repo second &&
+ test_migration repo "$to_format"
+ '
+
+ test_expect_success "$from_format -> $to_format: stash is retained" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ (
+ cd repo &&
+ test_commit initial A &&
+ echo foo >A &&
+ git stash push &&
+ echo bar >A &&
+ git stash push &&
+ git stash list >expect.reflog &&
+ test_migration . "$to_format" &&
+ git stash list >actual.reflog &&
+ test_cmp expect.reflog actual.reflog
+ )
+ '
+
+ test_expect_success "$from_format -> $to_format: skip reflog with --skip-reflog" '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=$from_format repo &&
+ test_commit -C repo initial &&
+ # we see that the repository contains reflogs.
+ git -C repo reflog --all >reflogs &&
+ test_line_count = 2 reflogs &&
+ test_migration repo "$to_format" true --no-reflog &&
+ # there should be no reflogs post migration.
+ git -C repo reflog --all >reflogs &&
+ test_must_be_empty reflogs
+ '
+ done
+done
+
+test_expect_success 'multiple reftable blocks with multiple entries' '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=files repo &&
+ test_commit -C repo first &&
+ printf "create refs/heads/ref-%d HEAD\n" $(test_seq 5000) >stdin &&
+ git -C repo update-ref --stdin <stdin &&
+ test_commit -C repo second &&
+ printf "update refs/heads/ref-%d HEAD\n" $(test_seq 3000) >stdin &&
+ git -C repo update-ref --stdin <stdin &&
+ test_migration repo reftable
+'
+
+test_expect_success 'migrating from files format deletes backend files' '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=files repo &&
+ test_commit -C repo first &&
+ git -C repo pack-refs --all &&
+ test_commit -C repo second &&
+ git -C repo update-ref ORIG_HEAD HEAD &&
+ git -C repo rev-parse HEAD >repo/.git/FETCH_HEAD &&
+
+ test_path_is_file repo/.git/HEAD &&
+ test_path_is_file repo/.git/ORIG_HEAD &&
+ test_path_is_file repo/.git/refs/heads/main &&
+ test_path_is_file repo/.git/packed-refs &&
+
+ test_migration repo reftable &&
+
+ echo "ref: refs/heads/.invalid" >expect &&
+ test_cmp expect repo/.git/HEAD &&
+ echo "this repository uses the reftable format" >expect &&
+ test_cmp expect repo/.git/refs/heads &&
+ test_path_is_file repo/.git/FETCH_HEAD &&
+ test_path_is_missing repo/.git/ORIG_HEAD &&
+ test_path_is_missing repo/.git/refs/heads/main &&
+ test_path_is_missing repo/.git/logs &&
+ test_path_is_missing repo/.git/packed-refs
+'
+
+test_expect_success 'migrating from reftable format deletes backend files' '
+ test_when_finished "rm -rf repo" &&
+ git init --ref-format=reftable repo &&
+ test_commit -C repo first &&
+
+ test_path_is_dir repo/.git/reftable &&
+ test_migration repo files &&
+
+ test_path_is_missing repo/.git/reftable &&
+ echo "ref: refs/heads/main" >expect &&
+ test_cmp expect repo/.git/HEAD &&
+ test_path_is_file repo/.git/packed-refs
+'
+
+test_done