| #!/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 | 
 | . "$TEST_DIRECTORY"/lib-terminal.sh | 
 |  | 
 | for cmd in create verify list-heads unbundle | 
 | do | 
 | 	test_expect_success "usage: git bundle $cmd needs an argument" ' | 
 | 		test_expect_code 129 git bundle $cmd | 
 | 	' | 
 | done | 
 |  | 
 | # 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 && | 
 |  | 
 | 	# If a different name hash function is used, then one fewer | 
 | 	# delta base is found and this counts a different number | 
 | 	# of objects after performing --fix-thin. | 
 | 	GIT_TEST_NAME_HASH_VERSION=1 \ | 
 | 		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 | 
 | ' | 
 |  | 
 | test_expect_success 'full bundle upto annotated tag' ' | 
 | 	git bundle create v2.bdl \ | 
 | 		v2 && | 
 |  | 
 | 	git bundle verify v2.bdl | | 
 | 		make_user_friendly_and_stable_output >actual && | 
 |  | 
 | 	format_and_save_expect <<-EOF && | 
 | 	The bundle contains this ref: | 
 | 	<TAG-2> refs/tags/v2 | 
 | 	The bundle records a complete history. | 
 | 	$HASH_MESSAGE | 
 | 	EOF | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | test_expect_success 'clone from full bundle upto annotated tag' ' | 
 | 	git clone --mirror v2.bdl tag-clone.git && | 
 | 	git -C tag-clone.git show-ref | | 
 | 		make_user_friendly_and_stable_output >actual && | 
 | 	cat >expect <<-\EOF && | 
 | 	<TAG-2> refs/tags/v2 | 
 | 	EOF | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | test_expect_success 'incremental bundle between two annotated tags' ' | 
 | 	git bundle create v1-v2.bdl \ | 
 | 		v1..v2 && | 
 |  | 
 | 	git bundle verify v1-v2.bdl | | 
 | 		make_user_friendly_and_stable_output >actual && | 
 |  | 
 | 	format_and_save_expect <<-EOF && | 
 | 	The bundle contains this ref: | 
 | 	<TAG-2> refs/tags/v2 | 
 | 	The bundle requires these 2 refs: | 
 | 	<COMMIT-E> Z | 
 | 	<COMMIT-B> Z | 
 | 	$HASH_MESSAGE | 
 | 	EOF | 
 | 	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_expect_success 'verify catches unreachable, broken prerequisites' ' | 
 | 	test_when_finished rm -rf clone-from clone-to && | 
 | 	git init clone-from && | 
 | 	( | 
 | 		cd clone-from && | 
 | 		git checkout -b base && | 
 | 		test_commit A && | 
 | 		git checkout -b tip && | 
 | 		git commit --allow-empty -m "will drop by shallow" && | 
 | 		git commit --allow-empty -m "will keep by shallow" && | 
 | 		git commit --allow-empty -m "for bundle, not clone" && | 
 | 		git bundle create tip.bundle tip~1..tip && | 
 | 		git reset --hard HEAD~1 && | 
 | 		git checkout base | 
 | 	) && | 
 | 	BAD_OID=$(git -C clone-from rev-parse tip~1) && | 
 | 	TIP_OID=$(git -C clone-from rev-parse tip) && | 
 | 	git clone --depth=1 --no-single-branch \ | 
 | 		"file://$(pwd)/clone-from" clone-to && | 
 | 	( | 
 | 		cd clone-to && | 
 |  | 
 | 		# Set up broken history by removing shallow markers | 
 | 		git update-ref -d refs/remotes/origin/tip && | 
 | 		rm .git/shallow && | 
 |  | 
 | 		# Verify should fail | 
 | 		test_must_fail git bundle verify \ | 
 | 			../clone-from/tip.bundle 2>err && | 
 | 		grep "some prerequisite commits .* are not connected" err && | 
 | 		test_line_count = 1 err && | 
 |  | 
 | 		# Unbundling should fail | 
 | 		test_must_fail git bundle unbundle \ | 
 | 			../clone-from/tip.bundle 2>err && | 
 | 		grep "some prerequisite commits .* are not connected" err && | 
 | 		test_line_count = 1 err | 
 | 	) | 
 | ' | 
 |  | 
 | test_expect_success 'bundle progress includes write phase' ' | 
 | 	GIT_PROGRESS_DELAY=0 \ | 
 | 		git bundle create --progress out.bundle --all 2>err && | 
 | 	grep 'Writing' err | 
 | ' | 
 |  | 
 | test_expect_success TTY 'create --quiet disables all bundle progress' ' | 
 | 	test_terminal env GIT_PROGRESS_DELAY=0 \ | 
 | 		git bundle create --quiet out.bundle --all 2>err && | 
 | 	test_must_be_empty err | 
 | ' | 
 |  | 
 | test_expect_success 'bundle progress with --no-quiet' ' | 
 | 	GIT_PROGRESS_DELAY=0 \ | 
 | 		git bundle create --no-quiet out.bundle --all 2>err && | 
 | 	grep "%" err | 
 | ' | 
 |  | 
 | test_expect_success 'create bundle with duplicate refnames' ' | 
 | 	git bundle create out.bdl "main" "main" && | 
 |  | 
 | 	git bundle list-heads out.bdl | | 
 | 		make_user_friendly_and_stable_output >actual && | 
 | 	cat >expect <<-\EOF && | 
 | 	<COMMIT-P> refs/heads/main | 
 | 	EOF | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | test_expect_success 'create bundle with duplicate refnames and --all' ' | 
 | 	git bundle create out.bdl --all "main" "main" && | 
 |  | 
 | 	git bundle list-heads out.bdl | | 
 | 		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 | 
 | 	<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 | 
 | 	EOF | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | test_expect_success 'create bundle with duplicate exlusion refnames' ' | 
 | 	git bundle create out.bdl "main" "main^!" && | 
 |  | 
 | 	git bundle list-heads out.bdl | | 
 | 		make_user_friendly_and_stable_output >actual && | 
 | 	cat >expect <<-\EOF && | 
 | 	<COMMIT-P> refs/heads/main | 
 | 	EOF | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | test_expect_success 'create bundle with duplicate refname short-form' ' | 
 | 	git bundle create out.bdl "main" "main" "refs/heads/main" "refs/heads/main" && | 
 |  | 
 | 	git bundle list-heads out.bdl | | 
 | 		make_user_friendly_and_stable_output >actual && | 
 | 	cat >expect <<-\EOF && | 
 | 	<COMMIT-P> refs/heads/main | 
 | 	EOF | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | test_expect_success 'read bundle over stdin' ' | 
 | 	git bundle create some.bundle HEAD && | 
 |  | 
 | 	git bundle verify - <some.bundle 2>err && | 
 | 	grep "<stdin> is okay" err && | 
 |  | 
 | 	git bundle list-heads some.bundle >expect && | 
 | 	git bundle list-heads - <some.bundle >actual && | 
 | 	test_cmp expect actual && | 
 |  | 
 | 	git bundle unbundle some.bundle >expect && | 
 | 	git bundle unbundle - <some.bundle >actual && | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | test_expect_success 'send a bundle to standard output' ' | 
 | 	git bundle create - --all HEAD >bundle-one && | 
 | 	mkdir -p down && | 
 | 	git -C down bundle create - --all HEAD >bundle-two && | 
 | 	git bundle verify bundle-one && | 
 | 	git bundle verify bundle-two && | 
 | 	git ls-remote bundle-one >expect && | 
 | 	git ls-remote bundle-two >actual && | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | test_expect_success 'unbundle outside of a repository' ' | 
 | 	git bundle create some.bundle HEAD && | 
 | 	echo "fatal: Need a repository to unbundle." >expect && | 
 | 	nongit test_must_fail git bundle unbundle "$(pwd)/some.bundle" 2>err && | 
 | 	test_cmp expect err | 
 | ' | 
 |  | 
 | test_expect_success 'list-heads outside of a repository' ' | 
 | 	git bundle create some.bundle HEAD && | 
 | 	cat >expect <<-EOF && | 
 | 	$(git rev-parse HEAD) HEAD | 
 | 	EOF | 
 | 	nongit git bundle list-heads "$(pwd)/some.bundle" >actual && | 
 | 	test_cmp expect actual | 
 | ' | 
 |  | 
 | for hash in sha1 sha256 | 
 | do | 
 | 	test_expect_success "list-heads with bundle using $hash" ' | 
 | 		test_when_finished "rm -rf hash" && | 
 | 		git init --object-format=$hash hash && | 
 | 		test_commit -C hash initial && | 
 | 		git -C hash bundle create hash.bundle HEAD && | 
 |  | 
 | 		cat >expect <<-EOF && | 
 | 		$(git -C hash rev-parse HEAD) HEAD | 
 | 		EOF | 
 | 		git bundle list-heads hash/hash.bundle >actual && | 
 | 		test_cmp expect actual | 
 | 	' | 
 | done | 
 |  | 
 | test_done |