diff options
Diffstat (limited to '')
-rwxr-xr-x | t/t6020-bundle-misc.sh | 562 |
1 files changed, 562 insertions, 0 deletions
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh new file mode 100755 index 0000000..8332051 --- /dev/null +++ b/t/t6020-bundle-misc.sh @@ -0,0 +1,562 @@ +#!/bin/sh +# +# Copyright (c) 2021 Jiang Xin +# + +test_description='Test git-bundle' + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-bundle.sh + +# Create a commit or tag and set the variable with the object ID. +test_commit_setvar () { + notick= + signoff= + indir= + merge= + tag= + var= + + while test $# != 0 + do + case "$1" in + --merge) + merge=t + ;; + --tag) + tag=t + ;; + --notick) + notick=t + ;; + --signoff) + signoff="$1" + ;; + -C) + shift + indir="$1" + ;; + -*) + echo >&2 "error: unknown option $1" + return 1 + ;; + *) + break + ;; + esac + shift + done + if test $# -lt 2 + then + echo >&2 "error: test_commit_setvar must have at least 2 arguments" + return 1 + fi + var=$1 + shift + indir=${indir:+"$indir"/} + if test -z "$notick" + then + test_tick + fi && + if test -n "$merge" + then + git ${indir:+ -C "$indir"} merge --no-edit --no-ff \ + ${2:+-m "$2"} "$1" && + oid=$(git ${indir:+ -C "$indir"} rev-parse HEAD) + elif test -n "$tag" + then + git ${indir:+ -C "$indir"} tag -m "$1" "$1" "${2:-HEAD}" && + oid=$(git ${indir:+ -C "$indir"} rev-parse "$1") + else + file=${2:-"$1.t"} && + echo "${3-$1}" >"$indir$file" && + git ${indir:+ -C "$indir"} add "$file" && + git ${indir:+ -C "$indir"} commit $signoff -m "$1" && + oid=$(git ${indir:+ -C "$indir"} rev-parse HEAD) + fi && + eval $var=$oid +} + +get_abbrev_oid () { + oid=$1 && + suffix=${oid#???????} && + oid=${oid%$suffix} && + if test -n "$oid" + then + echo "$oid" + else + echo "undefined-oid" + fi +} + +# Format the output of git commands to make a user-friendly and stable +# text. We can easily prepare the expect text without having to worry +# about future changes of the commit ID. +make_user_friendly_and_stable_output () { + sed \ + -e "s/$(get_abbrev_oid $A)[0-9a-f]*/<COMMIT-A>/g" \ + -e "s/$(get_abbrev_oid $B)[0-9a-f]*/<COMMIT-B>/g" \ + -e "s/$(get_abbrev_oid $C)[0-9a-f]*/<COMMIT-C>/g" \ + -e "s/$(get_abbrev_oid $D)[0-9a-f]*/<COMMIT-D>/g" \ + -e "s/$(get_abbrev_oid $E)[0-9a-f]*/<COMMIT-E>/g" \ + -e "s/$(get_abbrev_oid $F)[0-9a-f]*/<COMMIT-F>/g" \ + -e "s/$(get_abbrev_oid $G)[0-9a-f]*/<COMMIT-G>/g" \ + -e "s/$(get_abbrev_oid $H)[0-9a-f]*/<COMMIT-H>/g" \ + -e "s/$(get_abbrev_oid $I)[0-9a-f]*/<COMMIT-I>/g" \ + -e "s/$(get_abbrev_oid $J)[0-9a-f]*/<COMMIT-J>/g" \ + -e "s/$(get_abbrev_oid $K)[0-9a-f]*/<COMMIT-K>/g" \ + -e "s/$(get_abbrev_oid $L)[0-9a-f]*/<COMMIT-L>/g" \ + -e "s/$(get_abbrev_oid $M)[0-9a-f]*/<COMMIT-M>/g" \ + -e "s/$(get_abbrev_oid $N)[0-9a-f]*/<COMMIT-N>/g" \ + -e "s/$(get_abbrev_oid $O)[0-9a-f]*/<COMMIT-O>/g" \ + -e "s/$(get_abbrev_oid $P)[0-9a-f]*/<COMMIT-P>/g" \ + -e "s/$(get_abbrev_oid $TAG1)[0-9a-f]*/<TAG-1>/g" \ + -e "s/$(get_abbrev_oid $TAG2)[0-9a-f]*/<TAG-2>/g" \ + -e "s/$(get_abbrev_oid $TAG3)[0-9a-f]*/<TAG-3>/g" +} + +format_and_save_expect () { + sed -e 's/Z$//' >expect +} + +HASH_MESSAGE="The bundle uses this hash algorithm: $GIT_DEFAULT_HASH" + +# (C) (D, pull/1/head, topic/1) +# o --- o +# / \ (L) +# / \ o (H, topic/2) (M, tag:v2) +# / (F) \ / (N, tag:v3) +# / o --------- o (G, pull/2/head) o --- o --- o (release) +# / / \ \ / \ +# o --- o --- o -------- o -- o ------------------ o ------- o --- o (main) +# (A) (B) (E, tag:v1) (I) (J) (K) (O) (P) +# +test_expect_success 'setup' ' + # Try to make a stable fixed width for abbreviated commit ID, + # this fixed-width oid will be replaced with "<OID>". + git config core.abbrev 7 && + + # branch main: commit A & B + test_commit_setvar A "Commit A" main.txt && + test_commit_setvar B "Commit B" main.txt && + + # branch topic/1: commit C & D, refs/pull/1/head + git checkout -b topic/1 && + test_commit_setvar C "Commit C" topic-1.txt && + test_commit_setvar D "Commit D" topic-1.txt && + git update-ref refs/pull/1/head HEAD && + + # branch topic/1: commit E, tag v1 + git checkout main && + test_commit_setvar E "Commit E" main.txt && + test_commit_setvar --tag TAG1 v1 && + + # branch topic/2: commit F & G, refs/pull/2/head + git checkout -b topic/2 && + test_commit_setvar F "Commit F" topic-2.txt && + test_commit_setvar G "Commit G" topic-2.txt && + git update-ref refs/pull/2/head HEAD && + test_commit_setvar H "Commit H" topic-2.txt && + + # branch main: merge commit I & J + git checkout main && + test_commit_setvar --merge I topic/1 "Merge commit I" && + test_commit_setvar --merge J refs/pull/2/head "Merge commit J" && + + # branch main: commit K + git checkout main && + test_commit_setvar K "Commit K" main.txt && + + # branch release: + git checkout -b release && + test_commit_setvar L "Commit L" release.txt && + test_commit_setvar M "Commit M" release.txt && + test_commit_setvar --tag TAG2 v2 && + test_commit_setvar N "Commit N" release.txt && + test_commit_setvar --tag TAG3 v3 && + + # branch main: merge commit O, commit P + git checkout main && + test_commit_setvar --merge O tags/v2 "Merge commit O" && + test_commit_setvar P "Commit P" main.txt +' + +test_expect_success 'create bundle from special rev: main^!' ' + git bundle create special-rev.bdl "main^!" && + + git bundle list-heads special-rev.bdl | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-P> refs/heads/main + EOF + test_cmp expect actual && + + git bundle verify special-rev.bdl | + make_user_friendly_and_stable_output >actual && + format_and_save_expect <<-EOF && + The bundle contains this ref: + <COMMIT-P> refs/heads/main + The bundle requires this ref: + <COMMIT-O> Z + $HASH_MESSAGE + EOF + test_cmp expect actual && + + test_bundle_object_count special-rev.bdl 3 +' + +test_expect_success 'create bundle with --max-count option' ' + git bundle create max-count.bdl --max-count 1 \ + main \ + "^release" \ + refs/tags/v1 \ + refs/pull/1/head \ + refs/pull/2/head && + + git bundle verify max-count.bdl | + make_user_friendly_and_stable_output >actual && + format_and_save_expect <<-EOF && + The bundle contains these 2 refs: + <COMMIT-P> refs/heads/main + <TAG-1> refs/tags/v1 + The bundle requires this ref: + <COMMIT-O> Z + $HASH_MESSAGE + EOF + test_cmp expect actual && + + test_bundle_object_count max-count.bdl 4 +' + +test_expect_success 'create bundle with --since option' ' + git log -1 --pretty="%ad" $M >actual && + cat >expect <<-\EOF && + Thu Apr 7 15:26:13 2005 -0700 + EOF + test_cmp expect actual && + + git bundle create since.bdl \ + --since "Thu Apr 7 15:27:00 2005 -0700" \ + --all && + + git bundle verify since.bdl | + make_user_friendly_and_stable_output >actual && + format_and_save_expect <<-EOF && + The bundle contains these 5 refs: + <COMMIT-P> refs/heads/main + <COMMIT-N> refs/heads/release + <TAG-2> refs/tags/v2 + <TAG-3> refs/tags/v3 + <COMMIT-P> HEAD + The bundle requires these 2 refs: + <COMMIT-M> Z + <COMMIT-K> Z + $HASH_MESSAGE + EOF + test_cmp expect actual && + + test_bundle_object_count --thin since.bdl 13 +' + +test_expect_success 'create bundle 1 - no prerequisites' ' + # create bundle from args + git bundle create 1.bdl topic/1 topic/2 && + + # create bundle from stdin + cat >input <<-\EOF && + topic/1 + topic/2 + EOF + git bundle create stdin-1.bdl --stdin <input && + + format_and_save_expect <<-EOF && + The bundle contains these 2 refs: + <COMMIT-D> refs/heads/topic/1 + <COMMIT-H> refs/heads/topic/2 + The bundle records a complete history. + $HASH_MESSAGE + EOF + + # verify bundle, which has no prerequisites + git bundle verify 1.bdl | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + git bundle verify stdin-1.bdl | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + test_bundle_object_count 1.bdl 24 && + test_bundle_object_count stdin-1.bdl 24 +' + +test_expect_success 'create bundle 2 - has prerequisites' ' + # create bundle from args + git bundle create 2.bdl \ + --ignore-missing \ + ^topic/deleted \ + ^$D \ + ^topic/2 \ + release && + + # create bundle from stdin + # input has a non-exist reference: "topic/deleted" + cat >input <<-EOF && + ^topic/deleted + ^$D + ^topic/2 + EOF + git bundle create stdin-2.bdl \ + --ignore-missing \ + --stdin \ + release <input && + + format_and_save_expect <<-EOF && + The bundle contains this ref: + <COMMIT-N> refs/heads/release + The bundle requires these 3 refs: + <COMMIT-D> Z + <COMMIT-E> Z + <COMMIT-G> Z + $HASH_MESSAGE + EOF + + git bundle verify 2.bdl | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + git bundle verify stdin-2.bdl | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + test_bundle_object_count 2.bdl 16 && + test_bundle_object_count stdin-2.bdl 16 +' + +test_expect_success 'fail to verify bundle without prerequisites' ' + git init --bare test1.git && + + format_and_save_expect <<-\EOF && + error: Repository lacks these prerequisite commits: + error: <COMMIT-D> Z + error: <COMMIT-E> Z + error: <COMMIT-G> Z + EOF + + test_must_fail git -C test1.git bundle verify ../2.bdl 2>&1 | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + test_must_fail git -C test1.git bundle verify ../stdin-2.bdl 2>&1 | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual +' + +test_expect_success 'create bundle 3 - two refs, same object' ' + # create bundle from args + git bundle create --version=3 3.bdl \ + ^release \ + ^topic/1 \ + ^topic/2 \ + main \ + HEAD && + + # create bundle from stdin + cat >input <<-\EOF && + ^release + ^topic/1 + ^topic/2 + EOF + git bundle create --version=3 stdin-3.bdl \ + --stdin \ + main HEAD <input && + + format_and_save_expect <<-EOF && + The bundle contains these 2 refs: + <COMMIT-P> refs/heads/main + <COMMIT-P> HEAD + The bundle requires these 2 refs: + <COMMIT-M> Z + <COMMIT-K> Z + $HASH_MESSAGE + EOF + + git bundle verify 3.bdl | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + git bundle verify stdin-3.bdl | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + test_bundle_object_count 3.bdl 4 && + test_bundle_object_count stdin-3.bdl 4 +' + +test_expect_success 'create bundle 4 - with tags' ' + # create bundle from args + git bundle create 4.bdl \ + ^main \ + ^release \ + ^topic/1 \ + ^topic/2 \ + --all && + + # create bundle from stdin + cat >input <<-\EOF && + ^main + ^release + ^topic/1 + ^topic/2 + EOF + git bundle create stdin-4.bdl \ + --ignore-missing \ + --stdin \ + --all <input && + + cat >expect <<-EOF && + The bundle contains these 3 refs: + <TAG-1> refs/tags/v1 + <TAG-2> refs/tags/v2 + <TAG-3> refs/tags/v3 + The bundle records a complete history. + $HASH_MESSAGE + EOF + + git bundle verify 4.bdl | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + git bundle verify stdin-4.bdl | + make_user_friendly_and_stable_output >actual && + test_cmp expect actual && + + test_bundle_object_count 4.bdl 3 && + test_bundle_object_count stdin-4.bdl 3 +' + +test_expect_success 'clone from bundle' ' + git clone --mirror 1.bdl mirror.git && + git -C mirror.git show-ref | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-D> refs/heads/topic/1 + <COMMIT-H> refs/heads/topic/2 + EOF + test_cmp expect actual && + + git -C mirror.git fetch ../2.bdl "+refs/*:refs/*" && + git -C mirror.git show-ref | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-N> refs/heads/release + <COMMIT-D> refs/heads/topic/1 + <COMMIT-H> refs/heads/topic/2 + EOF + test_cmp expect actual && + + git -C mirror.git fetch ../3.bdl "+refs/*:refs/*" && + git -C mirror.git show-ref | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-P> refs/heads/main + <COMMIT-N> refs/heads/release + <COMMIT-D> refs/heads/topic/1 + <COMMIT-H> refs/heads/topic/2 + EOF + test_cmp expect actual && + + git -C mirror.git fetch ../4.bdl "+refs/*:refs/*" && + git -C mirror.git show-ref | + make_user_friendly_and_stable_output >actual && + cat >expect <<-\EOF && + <COMMIT-P> refs/heads/main + <COMMIT-N> refs/heads/release + <COMMIT-D> refs/heads/topic/1 + <COMMIT-H> refs/heads/topic/2 + <TAG-1> refs/tags/v1 + <TAG-2> refs/tags/v2 + <TAG-3> refs/tags/v3 + EOF + test_cmp expect actual +' + +test_expect_success 'unfiltered bundle with --objects' ' + git bundle create all-objects.bdl \ + --all --objects && + git bundle create all.bdl \ + --all && + + # Compare the headers of these files. + sed -n -e "/^$/q" -e "p" all.bdl >expect && + sed -n -e "/^$/q" -e "p" all-objects.bdl >actual && + test_cmp expect actual +' + +for filter in "blob:none" "tree:0" "tree:1" "blob:limit=100" +do + test_expect_success "filtered bundle: $filter" ' + test_when_finished rm -rf .git/objects/pack cloned unbundled && + git bundle create partial.bdl \ + --all \ + --filter=$filter && + + git bundle verify partial.bdl >unfiltered && + make_user_friendly_and_stable_output <unfiltered >actual && + + cat >expect <<-EOF && + The bundle contains these 10 refs: + <COMMIT-P> refs/heads/main + <COMMIT-N> refs/heads/release + <COMMIT-D> refs/heads/topic/1 + <COMMIT-H> refs/heads/topic/2 + <COMMIT-D> refs/pull/1/head + <COMMIT-G> refs/pull/2/head + <TAG-1> refs/tags/v1 + <TAG-2> refs/tags/v2 + <TAG-3> refs/tags/v3 + <COMMIT-P> HEAD + The bundle records a complete history. + $HASH_MESSAGE + The bundle uses this filter: $filter + EOF + test_cmp expect actual && + + test_config uploadpack.allowfilter 1 && + test_config uploadpack.allowanysha1inwant 1 && + git clone --no-local --filter=$filter --bare "file://$(pwd)" cloned && + + git init unbundled && + git -C unbundled bundle unbundle ../partial.bdl >ref-list.txt && + ls unbundled/.git/objects/pack/pack-*.promisor >promisor && + test_line_count = 1 promisor && + + # Count the same number of reachable objects. + reflist=$(git for-each-ref --format="%(objectname)") && + git rev-list --objects --filter=$filter --missing=allow-any \ + $reflist >expect && + for repo in cloned unbundled + do + git -C $repo rev-list --objects --missing=allow-any \ + $reflist >actual && + test_cmp expect actual || return 1 + done + ' +done + +# NEEDSWORK: 'git clone --bare' should be able to clone from a filtered +# bundle, but that requires a change to promisor/filter config options. +# For now, we fail gracefully with a helpful error. This behavior can be +# changed in the future to succeed as much as possible. +test_expect_success 'cloning from filtered bundle has useful error' ' + git bundle create partial.bdl \ + --all \ + --filter=blob:none && + test_must_fail git clone --bare partial.bdl partial 2>err && + grep "cannot clone from filtered bundle" err +' + +test_done |