"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Omar Polo <op@omarpolo.com>
Subject:
Re: send "unreachable" tags fails
To:
Stefan Sperling <stsp@stsp.name>
Cc:
gameoftrees@openbsd.org
Date:
Tue, 14 Sep 2021 12:07:25 +0200

Download raw body.

Thread
Stefan Sperling <stsp@stsp.name> writes:

> On Tue, Sep 14, 2021 at 09:45:49AM +0200, Omar Polo wrote:
>> Hello,
>> 
>> `got send' fails to send tags that were tagged on deleted branches.  I
>> don't know how widespread it is but for a couple of projects I'm used to
>> tag bugfix releases by branching off the last release, cherrypicking the
>> changes, tag the minor release and delete the branch.  I understand that
>> probably is not a workflow intended for got, and that I'm not in the
>> targeted audience, but anyway.
>> 
>> Here's how to reproduce.  I'm using a "testing" repo over at my site,
>> but any repository would do
>
> Thank you, Omar! Below is a regression test for this issue, and a fix.

Can confirm it works, thanks!

> There was an error in the load_tag() function: It didn't load any commits
> associated with the tag. So commits which were only reachable via a tag
> were never sent to the server. The server refused the pack file because
> the objects the tag was pointing at were missing. Any referenced objects
> are required to either already exist server-side or be shipped along in
> the pack file.
>
> diff 824d5f776c8195a3faa8c0b167888dbb99542482 /home/stsp/src/got
> blob - 4ab44ac470c99d3b1842ebaef994127428153e04
> file + lib/pack_create.c
> --- lib/pack_create.c
> +++ lib/pack_create.c
> @@ -527,7 +527,7 @@ load_tag(struct got_pack_metavec *v, struct got_object
>  
>  	switch (got_object_tag_get_object_type(tag)) {
>  	case GOT_OBJ_TYPE_COMMIT:
> -		err = load_commit(NULL, idset,
> +		err = load_commit(v, idset,
>  		    got_object_tag_get_object_id(tag), repo,
>  		    loose_obj_only, cancel_cb, cancel_arg);
>  		break;
> blob - ce7b085beed403260f19800f8e25f6d484e5e1d5
> file + regress/cmdline/send.sh
> --- regress/cmdline/send.sh
> +++ regress/cmdline/send.sh
> @@ -723,6 +723,124 @@ EOF
>  	test_done "$testroot" "$ret"
>  }
>  
> +test_send_tag_of_deleted_branch() {
> +	local testroot=`test_init send_tag_of_deleted_branch`
> +	local testurl=ssh://127.0.0.1/$testroot
> +	local commit_id=`git_show_head $testroot/repo`
> +
> +	got clone -q $testurl/repo $testroot/repo-clone
> +	ret="$?"
> +	if [ "$ret" != "0" ]; then
> +		echo "got clone command failed unexpectedly" >&2
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +	cat > $testroot/repo/.git/got.conf <<EOF
> +remote "origin" {
> +	protocol ssh
> +	server 127.0.0.1
> +	repository "$testroot/repo-clone"
> +}
> +EOF
> +	got branch -r $testroot/repo foo
> +
> +	# modify alpha on branch foo
> +	got checkout -b foo $testroot/repo $testroot/wt > /dev/null
> +	echo boo >> $testroot/wt/beta
> +	(cd $testroot/wt && got commit -m 'changed beta on branch foo' \
> +		> /dev/null)
> +	local commit_id2=`git_show_branch_head $testroot/repo foo`
> +
> +	# tag HEAD commit of branch foo
> +	got tag -r $testroot/repo -c foo -m '1.0' 1.0 > /dev/null
> +	tag_id=`got ref -r $testroot/repo -l | grep "^refs/tags/1.0" \
> +		| tr -d ' ' | cut -d: -f2`
> +
> +	# delete the branch; commit is now only reachable via tags/1.0
> +	got branch -r $testroot/repo -d foo > /dev/null
> +
> +	# unrelated change on master branch, then try sending this branch
> +	# and the tag
> +	echo "modified alpha" > $testroot/repo/alpha
> +	git_commit $testroot/repo -m "modified alpha"
> +	local commit_id3=`git_show_head $testroot/repo`
> +
> +	got send -q -r $testroot/repo -T > $testroot/stdout 2> $testroot/stderr
> +	ret="$?"
> +	if [ "$ret" != "0" ]; then
> +		echo "got send command failed unexpectedly" >&2
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +	
> +	echo -n > $testroot/stdout.expected
> +	cmp -s $testroot/stdout $testroot/stdout.expected
> +	ret="$?"
> +	if [ "$ret" != "0" ]; then
> +		diff -u $testroot/stdout.expected $testroot/stdout
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +
> +	got ref -l -r $testroot/repo > $testroot/stdout
> +	if [ "$ret" != "0" ]; then
> +		echo "got ref command failed unexpectedly" >&2
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +
> +	wt_uuid=`(cd $testroot/wt && got info | grep 'UUID:' | \
> +		cut -d ':' -f 2 | tr -d ' ')`
> +	echo "HEAD: refs/heads/master" > $testroot/stdout.expected
> +	echo "refs/got/worktree/base-$wt_uuid: $commit_id2" \
> +		>> $testroot/stdout.expected
> +	echo "refs/heads/master: $commit_id3" >> $testroot/stdout.expected
> +	echo "refs/remotes/origin/master: $commit_id3" \
> +		>> $testroot/stdout.expected
> +	echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
> +
> +	cmp -s $testroot/stdout $testroot/stdout.expected
> +	ret="$?"
> +	if [ "$ret" != "0" ]; then
> +		diff -u $testroot/stdout.expected $testroot/stdout
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +
> +	got ref -l -r $testroot/repo-clone > $testroot/stdout
> +	if [ "$ret" != "0" ]; then
> +		echo "got ref command failed unexpectedly" >&2
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +
> +	echo "HEAD: refs/heads/master" > $testroot/stdout.expected
> +	echo "refs/heads/master: $commit_id3" >> $testroot/stdout.expected
> +	echo "refs/remotes/origin/HEAD: refs/remotes/origin/master" \
> +		>> $testroot/stdout.expected
> +	echo "refs/remotes/origin/master: $commit_id" \
> +		>> $testroot/stdout.expected
> +	echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
> +
> +	cmp -s $testroot/stdout $testroot/stdout.expected
> +	ret="$?"
> +	if [ "$ret" != "0" ]; then
> +		diff -u $testroot/stdout.expected $testroot/stdout
> +		test_done "$testroot" "$ret"
> +		return 1
> +	fi
> +
> +	got tag -l -r $testroot/repo-clone | grep ^tag | sort > $testroot/stdout
> +	echo "tag 1.0 $tag_id" > $testroot/stdout.expected
> +
> +	cmp -s $testroot/stdout $testroot/stdout.expected
> +	ret="$?"
> +	if [ "$ret" != "0" ]; then
> +		diff -u $testroot/stdout.expected $testroot/stdout
> +	fi
> +	test_done "$testroot" "$ret"
> +}
> +
>  test_send_new_branch() {
>  	local testroot=`test_init send_new_branch`
>  	local testurl=ssh://127.0.0.1/$testroot
> @@ -1241,6 +1359,7 @@ run_test test_send_rebase_required_overwrite
>  run_test test_send_delete
>  run_test test_send_clone_and_send
>  run_test test_send_tags
> +run_test test_send_tag_of_deleted_branch
>  run_test test_send_new_branch
>  run_test test_send_all_branches
>  run_test test_send_to_empty_repo