From: Jiang Xin Date: Fri, 08 Jan 2021 14:45:12 GMT Subject: [PATCH v4 0/2] Improvements for git-bundle Message-ID: <20210108144514.24805-1-worldhello.net@gmail.com> In-Reply-To: From: Jiang Xin ## Two improvements for git-bundle 1. Commit "bundle: lost objects when removing duplicate pendings", which fixes command like: $ git bundle create 'master^!' 2. Commits "bundle: arguments can be read from stdin", which add "--stdin" option support for git-bundle, like: $ git bundle create &2 "args should be: " ++ 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//g" \ -+ -e "s/$B//g" \ -+ -e "s/$C//g" \ -+ -e "s/$D//g" \ -+ -e "s/$E//g" \ -+ -e "s/$F//g" \ -+ -e "s/$G//g" \ -+ -e "s/$H//g" \ -+ -e "s/$I//g" \ -+ -e "s/$J//g" \ -+ -e "s/$K//g" \ -+ -e "s/$L//g" \ -+ -e "s/$M//g" \ -+ -e "s/$N//g" \ -+ -e "s/$O//g" \ -+ -e "s/$P//g" \ ++ -e "s/$A//" \ ++ -e "s/$B//" \ ++ -e "s/$C//" \ ++ -e "s/$D//" \ ++ -e "s/$E//" \ ++ -e "s/$F//" \ ++ -e "s/$G//" \ ++ -e "s/$H//" \ ++ -e "s/$I//" \ ++ -e "s/$J//" \ ++ -e "s/$K//" \ ++ -e "s/$L//" \ ++ -e "s/$M//" \ ++ -e "s/$N//" \ ++ -e "s/$O//" \ ++ -e "s/$P//" \ ++ -e "s/$TAG1//" \ ++ -e "s/$TAG2//" \ ++ -e "s/$TAG3//" \ + -e "s/$(echo $A | cut -c1-7)[0-9a-f]*//g" \ + -e "s/$(echo $B | cut -c1-7)[0-9a-f]*//g" \ + -e "s/$(echo $C | cut -c1-7)[0-9a-f]*//g" \ @@ t/t6020-bundle-misc.sh (new) + -e "s/$(echo $N | cut -c1-7)[0-9a-f]*//g" \ + -e "s/$(echo $O | cut -c1-7)[0-9a-f]*//g" \ + -e "s/$(echo $P | cut -c1-7)[0-9a-f]*//g" \ -+ -e "s/$TAG1//g" \ -+ -e "s/$TAG2//g" \ -+ -e "s/$TAG3//g" \ + -e "s/$(echo $TAG1 | cut -c1-7)[0-9a-f]*//g" \ + -e "s/$(echo $TAG2 | cut -c1-7)[0-9a-f]*//g" \ + -e "s/$(echo $TAG3 | cut -c1-7)[0-9a-f]*//g" \ -+ -e "s/$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 "". ++ 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