From: Jiang Xin <zhiyou.jx@xxxxxxxxxxxxxxx> ## Two improvements for git-bundle 1. Commit "bundle: lost objects when removing duplicate pendings", which fixes command like: $ git bundle create <file> 'master^!' 2. Commits "bundle: arguments can be read from stdin", which add "--stdin" option support for git-bundle, like: $ git bundle create <file> <input ## Changes of v4 + Refactor t6020. ## Range diff of v3...v4 1: 9df48434f3 ! 1: 0abad6486a bundle: lost objects when removing duplicate pendings @@ t/t6020-bundle-misc.sh (new) + +. ./test-lib.sh + ++# Check count of objects in a bundle file. ++# We can use "--thin" opiton to check thin pack, which must be fixed by ++# command `git-index-pack --fix-thin --stdin`. +test_bundle_object_count () { ++ thin= && ++ if test "$1" = "--thin" ++ then ++ thin=yes ++ shift ++ fi && ++ if test $# -ne 2 ++ then ++ echo >&2 "args should be: <bundle> <count>" ++ return 1 ++ fi + bundle=$1 && + pack=${bundle%.bdl}.pack && + convert_bundle_to_pack <"$bundle" >"$pack" && -+ git index-pack "$pack" && -+ git verify-pack -v "$pack" >verify.out && -+ count=$(grep "^$OID_REGEX " verify.out | wc -l) && ++ if test -n "$thin" ++ then ++ test_must_fail git index-pack "$pack" && ++ mv "$pack" "$pack"-thin && ++ cat "$pack"-thin | ++ git index-pack --stdin --fix-thin "$pack" ++ else ++ git index-pack "$pack" ++ fi && ++ git verify-pack -v "$pack" >verify.out ++ if test $? -ne 0 ++ then ++ echo >&2 "error: fail to convert $bundle to $pack" ++ return 1 ++ fi ++ count=$(grep -c "^$OID_REGEX " verify.out) && + test $2 = $count && return 0 -+ echo object count for $bundle is $count, not $2 -+ return 1 -+} -+ -+ -+test_thin_bundle_object_count () { -+ bundle=$1 && -+ pack=${bundle%.bdl}.pack && -+ convert_bundle_to_pack <"$bundle" | -+ test_must_fail git index-pack --stdin "$pack" && -+ rm -f "$pack" && -+ convert_bundle_to_pack <"$bundle" | -+ git index-pack --stdin --fix-thin "$pack" && -+ git verify-pack -v "$pack" >verify.out && -+ count=$(grep "^$OID_REGEX " verify.out | wc -l) && -+ test $2 = $count && return 0 -+ echo object count for $bundle is $count, not $2 ++ echo >&2 "error: object count for $bundle is $count, not $2" + return 1 +} + ++# Display the pack data contained in the bundle file, bypassing the ++# header that contains the signature, prerequisites and references. +convert_bundle_to_pack () { + while read x && test -n "$x" + do @@ t/t6020-bundle-misc.sh (new) + cat +} + ++# 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=yes ++ ;; ++ --tag) ++ tag=yes ++ ;; ++ --notick) ++ notick=yes ++ ;; ++ --signoff) ++ signoff="$1" ++ ;; ++ -C) ++ indir="$2" ++ shift ++ ;; ++ -*) ++ echo >&2 "error: unknown option $1" ++ return 1 ++ ;; ++ *) ++ test -n "$var" && break ++ var=$1 ++ ;; ++ esac ++ shift ++ done && ++ indir=${indir:+"$indir"/} && ++ if test $# -eq 0 ++ then ++ echo >&2 "no args provided" ++ return 1 ++ fi && ++ 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" && ++ 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 ++} ++ ++ +# 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 and spaces of the output. +make_user_friendly_and_stable_output () { + sed \ -+ -e "s/ *\$//" \ -+ -e "s/$A/<COMMIT-A>/g" \ -+ -e "s/$B/<COMMIT-B>/g" \ -+ -e "s/$C/<COMMIT-C>/g" \ -+ -e "s/$D/<COMMIT-D>/g" \ -+ -e "s/$E/<COMMIT-E>/g" \ -+ -e "s/$F/<COMMIT-F>/g" \ -+ -e "s/$G/<COMMIT-G>/g" \ -+ -e "s/$H/<COMMIT-H>/g" \ -+ -e "s/$I/<COMMIT-I>/g" \ -+ -e "s/$J/<COMMIT-J>/g" \ -+ -e "s/$K/<COMMIT-K>/g" \ -+ -e "s/$L/<COMMIT-L>/g" \ -+ -e "s/$M/<COMMIT-M>/g" \ -+ -e "s/$N/<COMMIT-N>/g" \ -+ -e "s/$O/<COMMIT-O>/g" \ -+ -e "s/$P/<COMMIT-P>/g" \ ++ -e "s/$A/<COMMIT-A>/" \ ++ -e "s/$B/<COMMIT-B>/" \ ++ -e "s/$C/<COMMIT-C>/" \ ++ -e "s/$D/<COMMIT-D>/" \ ++ -e "s/$E/<COMMIT-E>/" \ ++ -e "s/$F/<COMMIT-F>/" \ ++ -e "s/$G/<COMMIT-G>/" \ ++ -e "s/$H/<COMMIT-H>/" \ ++ -e "s/$I/<COMMIT-I>/" \ ++ -e "s/$J/<COMMIT-J>/" \ ++ -e "s/$K/<COMMIT-K>/" \ ++ -e "s/$L/<COMMIT-L>/" \ ++ -e "s/$M/<COMMIT-M>/" \ ++ -e "s/$N/<COMMIT-N>/" \ ++ -e "s/$O/<COMMIT-O>/" \ ++ -e "s/$P/<COMMIT-P>/" \ ++ -e "s/$TAG1/<TAG-1>/" \ ++ -e "s/$TAG2/<TAG-2>/" \ ++ -e "s/$TAG3/<TAG-3>/" \ + -e "s/$(echo $A | cut -c1-7)[0-9a-f]*/<OID-A>/g" \ + -e "s/$(echo $B | cut -c1-7)[0-9a-f]*/<OID-B>/g" \ + -e "s/$(echo $C | cut -c1-7)[0-9a-f]*/<OID-C>/g" \ @@ t/t6020-bundle-misc.sh (new) + -e "s/$(echo $N | cut -c1-7)[0-9a-f]*/<OID-N>/g" \ + -e "s/$(echo $O | cut -c1-7)[0-9a-f]*/<OID-O>/g" \ + -e "s/$(echo $P | cut -c1-7)[0-9a-f]*/<OID-P>/g" \ -+ -e "s/$TAG1/<TAG-1>/g" \ -+ -e "s/$TAG2/<TAG-2>/g" \ -+ -e "s/$TAG3/<TAG-3>/g" \ + -e "s/$(echo $TAG1 | cut -c1-7)[0-9a-f]*/<OID-TAG-1>/g" \ + -e "s/$(echo $TAG2 | cut -c1-7)[0-9a-f]*/<OID-TAG-2>/g" \ + -e "s/$(echo $TAG3 | cut -c1-7)[0-9a-f]*/<OID-TAG-3>/g" \ -+ -e "s/$ZERO_OID/<ZERO-OID>/g" ++ -e "s/ *\$//" +} + +# (C) (D, pull/1/head, topic/1) @@ t/t6020-bundle-misc.sh (new) +# (A) (B) (E, tag:v1) (I) (J) (K) (O) (P) +# +test_expect_success 'setup' ' -+ # commit A & B -+ cat >main.txt <<-EOF && -+ Commit A -+ EOF -+ git add main.txt && -+ test_tick && -+ git commit -m "Commit A" && ++ # 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 && + -+ cat >main.txt <<-EOF && -+ Commit B -+ EOF -+ git add main.txt && -+ test_tick && -+ git commit -m "Commit B" && -+ A=$(git rev-parse HEAD~) && -+ B=$(git rev-parse HEAD) && ++ # branch main: commit A & B ++ test_commit_setvar A "Commit A" main.txt && ++ test_commit_setvar B "Commit B" main.txt && + -+ # branch topic/1 ++ # branch topic/1: commit C & D, refs/pull/1/head + git checkout -b topic/1 && -+ cat >topic-1.txt <<-EOF && -+ Commit C -+ EOF -+ git add topic-1.txt && -+ test_tick && -+ git commit -m "Commit C" && -+ -+ cat >topic-1.txt <<-EOF && -+ Commit D -+ EOF -+ git add -u && -+ test_tick && -+ git commit -m "Commit D" && ++ 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 && -+ C=$(git rev-parse topic/1~) && -+ D=$(git rev-parse topic/1) && + -+ # commit E ++ # branch topic/1: commit E, tag v1 + git checkout main && -+ cat >main.txt <<-EOF && -+ Commit E -+ EOF -+ git add main.txt && -+ test_tick && -+ git commit -m "Commit E" && -+ E=$(git rev-parse HEAD) && -+ test_tick && -+ git tag -m "v1" v1 HEAD && -+ TAG1=$(git rev-parse refs/tags/v1) && -+ -+ # branch topic/2 -+ git checkout -b topic/2 && -+ cat >topic-2.txt <<-EOF && -+ Commit F -+ EOF -+ git add topic-2.txt && -+ test_tick && -+ git commit -m "Commit F" && ++ test_commit_setvar E "Commit E" main.txt && ++ test_commit_setvar TAG1 --tag v1 && + -+ cat >topic-2.txt <<-EOF && -+ Commit G -+ EOF -+ git add -u && -+ test_tick && -+ git commit -m "Commit G" && ++ # 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 && + -+ cat >topic-2.txt <<-EOF && -+ Commit H -+ EOF -+ git add -u && -+ test_tick && -+ git commit -m "Commit H" && -+ F=$(git rev-parse topic/2~2) && -+ G=$(git rev-parse topic/2~) && -+ H=$(git rev-parse topic/2) && -+ -+ # merge commit I & J ++ # branch main: merge commit I & J + git checkout main && -+ test_tick && -+ git merge --no-ff --no-edit topic/1 && -+ test_tick && -+ git merge --no-ff --no-edit refs/pull/2/head && -+ I=$(git rev-parse HEAD~) && -+ J=$(git rev-parse HEAD) && -+ -+ # commit K ++ test_commit_setvar I --merge topic/1 "Merge commit I" && ++ test_commit_setvar J --merge refs/pull/2/head "Merge commit J" && ++ ++ # branch main: commit K + git checkout main && -+ cat >main.txt <<-EOF && -+ Commit K -+ EOF -+ git add main.txt && -+ test_tick && -+ git commit -m "Commit K" && -+ K=$(git rev-parse HEAD) && ++ test_commit_setvar K "Commit K" main.txt && + -+ # branch release ++ # branch release: + git checkout -b release && -+ cat >release.txt <<-EOF && -+ Commit L -+ EOF -+ git add release.txt && -+ test_tick && -+ git commit -m "Commit L" && ++ test_commit_setvar L "Commit L" release.txt && ++ test_commit_setvar M "Commit M" release.txt && ++ test_commit_setvar TAG2 --tag v2 && ++ test_commit_setvar N "Commit N" release.txt && ++ test_commit_setvar TAG3 --tag v3 && + -+ cat >release.txt <<-EOF && -+ Commit M -+ EOF -+ git add -u && -+ test_tick && -+ git commit -m "Commit M" && -+ test_tick && -+ git tag -m "v2" v2 HEAD && -+ -+ cat >release.txt <<-EOF && -+ Commit N -+ EOF -+ git add -u && -+ test_tick && -+ git commit -m "Commit N" && -+ test_tick && -+ git tag -m "v3" v3 HEAD && -+ L=$(git rev-parse HEAD~2) && -+ M=$(git rev-parse HEAD~) && -+ N=$(git rev-parse HEAD) && -+ TAG2=$(git rev-parse refs/tags/v2) && -+ TAG3=$(git rev-parse refs/tags/v3) && -+ -+ # merge commit O -+ git checkout main && -+ test_tick && -+ git merge --no-ff --no-edit tags/v2 && -+ O=$(git rev-parse HEAD) && -+ -+ # commit P ++ # branch main: merge commit O, commit P + git checkout main && -+ cat >main.txt <<-EOF && -+ Commit P -+ EOF -+ git add main.txt && -+ test_tick && -+ git commit -m "Commit P" && -+ P=$(git rev-parse HEAD) ++ test_commit_setvar O --merge tags/v2 "Merge commit O" && ++ test_commit_setvar P "Commit P" main.txt +' + +test_expect_success 'create bundle from special rev: main^!' ' @@ t/t6020-bundle-misc.sh (new) +' + +test_expect_success 'create bundle with --since option' ' ++ since="Thu Apr 7 15:26:13 2005 -0700" && ++ git log -1 --pretty="%ad" $M >actual && ++ echo "$since" >expect && ++ test_cmp expect actual && ++ + git bundle create since.bdl \ -+ --since "Thu Apr 7 15:26:13 2005 -0700" \ -+ --all && ++ --since "$since" --all && + + git bundle list-heads since.bdl | + make_user_friendly_and_stable_output >actual && @@ t/t6020-bundle-misc.sh (new) + EOF + test_i18ncmp expect actual && + -+ test_thin_bundle_object_count since.bdl 16 ++ test_bundle_object_count --thin since.bdl 16 +' + +test_expect_success 'create bundle 1 - no prerequisites' ' 2: 86ad41e4d4 = 2: 48ef4aa44e bundle: arguments can be read from stdin -- Jiang Xin (2): bundle: lost objects when removing duplicate pendings bundle: arguments can be read from stdin bundle.c | 111 ++++---- object.c | 10 +- t/t5607-clone-bundle.sh | 4 +- t/t6020-bundle-misc.sh | 546 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 614 insertions(+), 57 deletions(-) create mode 100755 t/t6020-bundle-misc.sh -- 2.30.0.2.g06d2f50715