make 'got fetch' restore our copy of the remote HEAD if the copy was deleted
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 153 154 155 156 157 158 159 160 161 162 163 164 165
diff --git a/got/got.c b/got/got.c
index 8c3efa9..69c9927 100644
--- a/got/got.c
+++ b/got/got.c
@@ -1508,33 +1508,54 @@ update_symref(const char *refname, struct got_reference *target_ref,
{
const struct got_error *err = NULL, *unlock_err;
struct got_reference *symref;
+ int symref_is_locked = 0;
err = got_ref_open(&symref, repo, refname, 1);
- if (err)
- return err;
+ if (err) {
+ if (err->code != GOT_ERR_NOT_REF)
+ return err;
+ err = got_ref_alloc_symref(&symref, refname, target_ref);
+ if (err)
+ goto done;
- if (strcmp(got_ref_get_symref_target(symref),
- got_ref_get_name(target_ref)) == 0)
- goto done;
+ err = got_ref_write(symref, repo);
+ if (err)
+ goto done;
- err = got_ref_change_symref(symref, got_ref_get_name(target_ref));
- if (err)
- goto done;
+ if (verbosity >= 0)
+ printf("Created reference %s: %s\n",
+ got_ref_get_name(symref),
+ got_ref_get_symref_target(symref));
+ } else {
+ symref_is_locked = 1;
- err = got_ref_write(symref, repo);
- if (err)
- goto done;
+ if (strcmp(got_ref_get_symref_target(symref),
+ got_ref_get_name(target_ref)) == 0)
+ goto done;
- if (verbosity >= 0)
- printf("Updated reference %s: %s\n", got_ref_get_name(symref),
- got_ref_get_symref_target(symref));
+ err = got_ref_change_symref(symref,
+ got_ref_get_name(target_ref));
+ if (err)
+ goto done;
+
+ err = got_ref_write(symref, repo);
+ if (err)
+ goto done;
+
+ if (verbosity >= 0)
+ printf("Updated reference %s: %s\n",
+ got_ref_get_name(symref),
+ got_ref_get_symref_target(symref));
+
+ }
done:
- unlock_err = got_ref_unlock(symref);
- if (unlock_err && err == NULL)
- err = unlock_err;
+ if (symref_is_locked) {
+ unlock_err = got_ref_unlock(symref);
+ if (unlock_err && err == NULL)
+ err = unlock_err;
+ }
got_ref_close(symref);
return err;
- return NULL;
}
__dead static void
@@ -1912,13 +1933,7 @@ cmd_fetch(int argc, char *argv[])
if (pack_hash == NULL) {
if (verbosity >= 0)
printf("Already up-to-date\n");
- if (delete_refs)
- error = delete_missing_refs(&refs, &symrefs,
- remote, verbosity, repo);
- goto done;
- }
-
- if (verbosity >= 0) {
+ } else if (verbosity >= 0) {
error = got_object_id_str(&id_str, pack_hash);
if (error)
goto done;
diff --git a/regress/cmdline/fetch.sh b/regress/cmdline/fetch.sh
index 4efa1f0..d46a151 100755
--- a/regress/cmdline/fetch.sh
+++ b/regress/cmdline/fetch.sh
@@ -889,7 +889,63 @@ function test_fetch_update_headref {
diff -u $testroot/stdout.expected $testroot/stdout
fi
test_done "$testroot" "$ret"
+}
+
+function test_fetch_headref_deleted_locally {
+ local testroot=`test_init fetch_headref_deleted_locally`
+ 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
+
+ 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/remotes/origin/HEAD: refs/remotes/origin/master" \
+ >> $testroot/stdout.expected
+ echo "refs/remotes/origin/master: $commit_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 -r $testroot/repo-clone -d refs/remotes/origin/HEAD
+
+ got fetch -q -r $testroot/repo-clone
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got fetch command failed unexpectedly" >&2
+ 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
+ # refs/remotes/origin/HEAD has been restored:
+ echo "refs/remotes/origin/HEAD: refs/remotes/origin/master" \
+ >> $testroot/stdout.expected
+ echo "refs/remotes/origin/master: $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
@@ -902,3 +958,4 @@ run_test test_fetch_update_tag
run_test test_fetch_reference
run_test test_fetch_replace_symref
run_test test_fetch_update_headref
+run_test test_fetch_headref_deleted_locally