commit f1bcca348e0d038b29d4d9bc6c87cbccf6893265 from: Stefan Sperling date: Wed Mar 25 16:02:28 2020 UTC make 'got fetch' update our copy of the remote HEAD in case it has changed commit - d7b899ab022b3f7c7a42ed1338efa4ad6be626c8 commit + f1bcca348e0d038b29d4d9bc6c87cbccf6893265 blob - b02072bccaf3d9b6fd8fbcc856402702d6307ba0 blob + 96e6346e20d7ac287590a46af4a3f785b7fc7f4c --- got/got.c +++ got/got.c @@ -1501,7 +1501,42 @@ done: free(new_id_str); return err; } + +static const struct got_error * +update_symref(const char *refname, struct got_reference *target_ref, + int verbosity, struct got_repository *repo) +{ + const struct got_error *err = NULL, *unlock_err; + struct got_reference *symref; + + err = got_ref_open(&symref, repo, refname, 1); + if (err) + return err; + + if (strcmp(got_ref_get_symref_target(symref), + got_ref_get_name(target_ref)) == 0) + goto done; + 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; + got_ref_close(symref); + return err; + return NULL; +} + __dead static void usage_fetch(void) { @@ -1895,8 +1930,58 @@ cmd_fetch(int argc, char *argv[]) } } } - if (delete_refs) + if (delete_refs) { error = delete_missing_refs(&refs, verbosity, repo); + if (error) + goto done; + } + + if (!remote->mirror_references) { + /* Update remote HEAD reference if the server provided one. */ + TAILQ_FOREACH(pe, &symrefs, entry) { + struct got_reference *target_ref; + const char *refname = pe->path; + const char *target = pe->data; + char *remote_refname = NULL, *remote_target = NULL; + + if (strcmp(refname, GOT_REF_HEAD) != 0) + continue; + + if (strncmp("refs/heads/", target, 11) != 0) + continue; + + if (asprintf(&remote_refname, "refs/remotes/%s/%s", + remote->name, refname) == -1) { + error = got_error_from_errno("asprintf"); + goto done; + } + if (asprintf(&remote_target, "refs/remotes/%s/%s", + remote->name, target + 11) == -1) { + error = got_error_from_errno("asprintf"); + free(remote_refname); + goto done; + } + + error = got_ref_open(&target_ref, repo, remote_target, + 0); + if (error) { + free(remote_refname); + free(remote_target); + if (error->code == GOT_ERR_NOT_REF) { + error = NULL; + continue; + } + goto done; + } + error = update_symref(remote_refname, target_ref, + verbosity, repo); + free(remote_refname); + free(remote_target); + got_ref_close(target_ref); + if (error) + goto done; + } + } done: if (fetchpid > 0) { if (kill(fetchpid, SIGTERM) == -1) blob - 404c994afe6baff215d08dc8f14a1f9437434dac blob + e4a422fced01a3e564e433af5872e46fb304c6af --- regress/cmdline/fetch.sh +++ regress/cmdline/fetch.sh @@ -207,7 +207,7 @@ function test_fetch_branch { echo "HEAD: refs/heads/master" > $testroot/stdout.expected echo "refs/heads/foo: $commit_id3" >> $testroot/stdout.expected echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected - echo "refs/remotes/origin/HEAD: refs/remotes/origin/master" \ + echo "refs/remotes/origin/HEAD: refs/remotes/origin/foo" \ >> $testroot/stdout.expected echo "refs/remotes/origin/foo: $commit_id3" >> $testroot/stdout.expected # refs/remotes/origin/master is umodified because it wasn't fetched @@ -247,7 +247,7 @@ function test_fetch_branch { echo "HEAD: refs/heads/master" > $testroot/stdout.expected echo "refs/heads/foo: $commit_id3" >> $testroot/stdout.expected echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected - echo "refs/remotes/origin/HEAD: refs/remotes/origin/master" \ + echo "refs/remotes/origin/HEAD: refs/remotes/origin/foo" \ >> $testroot/stdout.expected echo "refs/remotes/origin/foo: $commit_id3" >> $testroot/stdout.expected echo "refs/remotes/origin/master: $commit_id2" \ @@ -813,12 +813,81 @@ function test_fetch_replace_symref { 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" + +} + +function test_fetch_update_headref { + local testroot=`test_init fetch_update_headref` + 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 -c refs/heads/master refs/heads/foo + got ref -r $testroot/repo -s refs/heads/foo HEAD + got ref -l -r $testroot/repo > $testroot/stdout + + echo "HEAD: refs/heads/foo" > $testroot/stdout.expected + echo "refs/heads/foo: $commit_id" >> $testroot/stdout.expected + echo "refs/heads/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 fetch -q -r $testroot/repo-clone + + got ref -l -r $testroot/repo-clone > $testroot/stdout + + echo "HEAD: refs/heads/master" > $testroot/stdout.expected + echo "refs/heads/foo: $commit_id" >> $testroot/stdout.expected + echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected + echo "refs/remotes/origin/HEAD: refs/remotes/origin/foo" \ + >> $testroot/stdout.expected + echo "refs/remotes/origin/foo: $commit_id" \ + >> $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" } @@ -832,3 +901,4 @@ run_test test_fetch_delete_branch run_test test_fetch_update_tag run_test test_fetch_reference run_test test_fetch_replace_symref +run_test test_fetch_update_headref