Commit Diff


commit - ecdc3b498ad54d952c807b07a04c0cdb2b998f03
commit + e8a967e0cafdb6604275a9cbfcce988d4f363ef5
blob - cd12b5ed30dbe248b20f407ac20e93f91e120177
blob + 0420f2eb7bce0a7e9766b05bb32d65d93f222c90
--- got/got.c
+++ got/got.c
@@ -1422,21 +1422,17 @@ update_ref(struct got_reference *ref, struct got_objec
 	}
 
 	if (got_ref_is_symbolic(ref)) {
-		struct got_reference *new_ref;
-		err = got_ref_alloc(&new_ref, got_ref_get_name(ref), new_id);
-		if (err)
-			goto done;
-		err = got_ref_delete(ref, repo);
-		if (err)
-			goto done;
 		if (verbosity >= 0) {
-			printf("Deleted reference %s: %s\n",
+			printf("Replacing reference %s: %s\n",
 			    got_ref_get_name(ref),
 			    got_ref_get_symref_target(ref));
 		}
-		err = got_ref_write(new_ref, repo);
+		err = got_ref_change_symref_to_ref(ref, new_id);
 		if (err)
 			goto done;
+		err = got_ref_write(ref, repo);
+		if (err)
+			goto done;
 	} else {
 		err = got_ref_resolve(&old_id, repo, ref);
 		if (err)
blob - da0da7b7bf5a3d15f4fc771d125303ba08d29bbd
blob + df306d5d03225bb3a1a0991de83bb445533c95be
--- include/got_reference.h
+++ include/got_reference.h
@@ -123,6 +123,13 @@ got_ref_change_ref(struct got_reference *, struct got_
 const struct got_error *got_ref_change_symref(struct got_reference *,
     char *);
 
+/*
+ * Change a symbolic reference into a regular reference which points to
+ * the provided object ID.
+ */
+const struct got_error *got_ref_change_symref_to_ref(struct got_reference *,
+    struct got_object_id *);
+
 /* Write a reference to its on-disk path in the repository. */
 const struct got_error *got_ref_write(struct got_reference *,
     struct got_repository *);
blob - ff1f037375b654994fbb0552899cb13e8766cdbb
blob + 86409d0ebedc1d35c6333f13f4f8267d21581671
--- lib/reference.c
+++ lib/reference.c
@@ -1007,6 +1007,19 @@ got_ref_change_symref(struct got_reference *ref, char 
 }
 
 const struct got_error *
+got_ref_change_symref_to_ref(struct got_reference *symref,
+    struct got_object_id *id)
+{
+	if ((symref->flags & GOT_REF_IS_SYMBOLIC) == 0)
+		return got_error(GOT_ERR_BAD_REF_TYPE);
+
+	symref->ref.ref.name = symref->ref.symref.name;
+	memcpy(symref->ref.ref.sha1, id->sha1, SHA1_DIGEST_LENGTH);
+	symref->flags &= ~GOT_REF_IS_SYMBOLIC;
+	return NULL;
+}
+
+const struct got_error *
 got_ref_write(struct got_reference *ref, struct got_repository *repo)
 {
 	const struct got_error *err = NULL, *unlock_err = NULL;
blob - d62e1ba6753013cbf06768c9b370cf784c5224a9
blob + b59b39ef20a710f192c51ed6560b8c1b58bb3e67
--- regress/cmdline/fetch.sh
+++ regress/cmdline/fetch.sh
@@ -718,12 +718,77 @@ function test_fetch_reference {
 	echo "refs/remotes/origin/master: $commit_id2" \
 		>> $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
+	fi
+	test_done "$testroot" "$ret"
+
+}
+
+function test_fetch_replace_symref {
+	local testroot=`test_init fetch_replace_symref`
+	local testurl=ssh://127.0.0.1/$testroot
+	local commit_id=`git_show_head $testroot/repo`
+
+	got clone -m -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
+
+	got ref -r $testroot/repo refs/hoo/boo/zoo $commit_id
+	got ref -r $testroot/repo-clone -s refs/hoo/boo/zoo refs/heads/master
+
+	got ref -l -r $testroot/repo-clone > $testroot/stdout
+
+	echo "HEAD: refs/heads/master" > $testroot/stdout.expected
+	echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected
+	echo "refs/hoo/boo/zoo: refs/heads/master" >> $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 fetch -r $testroot/repo-clone -R refs/hoo \
+		2> $testroot/stderr | grep ^Replacing > $testroot/stdout
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		echo "got fetch command failed unexpectedly" >&2
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	echo "Replacing reference refs/hoo/boo/zoo: refs/heads/master" \
+		> $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
+
+	echo "HEAD: refs/heads/master" > $testroot/stdout.expected
+	echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected
+	echo "refs/hoo/boo/zoo: $commit_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"
 
 }
@@ -736,3 +801,4 @@ run_test test_fetch_empty_packfile
 run_test test_fetch_delete_branch
 run_test test_fetch_update_tag
 run_test test_fetch_reference
+run_test test_fetch_replace_symref