make replacing symrefs actually work in 'got fetch'
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
diff --git a/got/got.c b/got/got.c
index cd12b5e..0420f2e 100644
--- a/got/got.c
+++ b/got/got.c
@@ -1422,19 +1422,15 @@ update_ref(struct got_reference *ref, struct got_object_id *new_id,
}
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 {
diff --git a/include/got_reference.h b/include/got_reference.h
index da0da7b..df306d5 100644
--- a/include/got_reference.h
+++ b/include/got_reference.h
@@ -123,6 +123,13 @@ got_ref_change_ref(struct got_reference *, struct got_object_id *);
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 *);
diff --git a/lib/reference.c b/lib/reference.c
index ff1f037..86409d0 100644
--- a/lib/reference.c
+++ b/lib/reference.c
@@ -1007,6 +1007,19 @@ got_ref_change_symref(struct got_reference *ref, char *refname)
}
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;
diff --git a/regress/cmdline/fetch.sh b/regress/cmdline/fetch.sh
index d62e1ba..b59b39e 100755
--- a/regress/cmdline/fetch.sh
+++ b/regress/cmdline/fetch.sh
@@ -728,6 +728,71 @@ function test_fetch_reference {
}
+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"
+
+}
+
run_test test_fetch_basic
run_test test_fetch_list
run_test test_fetch_branch
@@ -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