From: Junio C Hamano Date: Fri, 25 Aug 2017 21:41:13 +0000 (-0700) Subject: Merge branch 'nd/worktree-kill-parse-ref' into next X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/a5da82b2ea791677164ccd4a479ce2997bb2a56e?hp=-c Merge branch 'nd/worktree-kill-parse-ref' into next "git branch -M a b" while on a branch that is completely unrelated to either branch a or branch b misbehaved when multiple worktree was in use. This has been fixed. * nd/worktree-kill-parse-ref: branch: fix branch renaming not updating HEADs correctly --- a5da82b2ea791677164ccd4a479ce2997bb2a56e diff --combined branch.c index ce1f8bb58e,dc5c8aabde..703ded69ca --- a/branch.c +++ b/branch.c @@@ -1,6 -1,5 +1,6 @@@ #include "git-compat-util.h" #include "cache.h" +#include "config.h" #include "branch.h" #include "refs.h" #include "remote.h" @@@ -25,7 -24,8 +25,7 @@@ static int find_tracked_branch(struct r } else { free(tracking->spec.src); if (tracking->src) { - free(tracking->src); - tracking->src = NULL; + FREE_AND_NULL(tracking->src); } } tracking->spec.src = NULL; @@@ -90,24 -90,24 +90,24 @@@ int install_branch_config(int flag, con if (shortname) { if (origin) printf_ln(rebasing ? - _("Branch %s set up to track remote branch %s from %s by rebasing.") : - _("Branch %s set up to track remote branch %s from %s."), + _("Branch '%s' set up to track remote branch '%s' from '%s' by rebasing.") : + _("Branch '%s' set up to track remote branch '%s' from '%s'."), local, shortname, origin); else printf_ln(rebasing ? - _("Branch %s set up to track local branch %s by rebasing.") : - _("Branch %s set up to track local branch %s."), + _("Branch '%s' set up to track local branch '%s' by rebasing.") : + _("Branch '%s' set up to track local branch '%s'."), local, shortname); } else { if (origin) printf_ln(rebasing ? - _("Branch %s set up to track remote ref %s by rebasing.") : - _("Branch %s set up to track remote ref %s."), + _("Branch '%s' set up to track remote ref '%s' by rebasing.") : + _("Branch '%s' set up to track remote ref '%s'."), local, remote); else printf_ln(rebasing ? - _("Branch %s set up to track local ref %s by rebasing.") : - _("Branch %s set up to track local ref %s."), + _("Branch '%s' set up to track local ref '%s' by rebasing.") : + _("Branch '%s' set up to track local ref '%s'."), local, remote); } } @@@ -191,9 -191,9 +191,9 @@@ int validate_new_branchname(const char if (!attr_only) { const char *head; - unsigned char sha1[20]; + struct object_id oid; - head = resolve_ref_unsafe("HEAD", 0, sha1, NULL); + head = resolve_ref_unsafe("HEAD", 0, oid.hash, NULL); if (!is_bare_repository() && head && !strcmp(head, ref->buf)) die(_("Cannot force update the current branch.")); } @@@ -233,8 -233,8 +233,8 @@@ void create_branch(const char *name, co int quiet, enum branch_track track) { struct commit *commit; - unsigned char sha1[20]; - char *real_ref, msg[PATH_MAX + 20]; + struct object_id oid; + char *real_ref; struct strbuf ref = STRBUF_INIT; int forcing = 0; int dont_change_ref = 0; @@@ -253,7 -253,7 +253,7 @@@ } real_ref = NULL; - if (get_sha1(start_name, sha1)) { + if (get_oid(start_name, &oid)) { if (explicit_tracking) { if (advice_set_upstream_failure) { error(_(upstream_missing), start_name); @@@ -265,7 -265,7 +265,7 @@@ die(_("Not a valid object name: '%s'."), start_name); } - switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) { + switch (dwim_ref(start_name, strlen(start_name), oid.hash, &real_ref)) { case 0: /* Not branching from any existing branch */ if (explicit_tracking) @@@ -286,9 -286,16 +286,9 @@@ break; } - if ((commit = lookup_commit_reference(sha1)) == NULL) + if ((commit = lookup_commit_reference(&oid)) == NULL) die(_("Not a valid branch point: '%s'."), start_name); - hashcpy(sha1, commit->object.oid.hash); - - if (forcing) - snprintf(msg, sizeof msg, "branch: Reset to %s", - start_name); - else if (!dont_change_ref) - snprintf(msg, sizeof msg, "branch: Created from %s", - start_name); + oidcpy(&oid, &commit->object.oid); if (reflog) log_all_ref_updates = LOG_REFS_NORMAL; @@@ -296,23 -303,16 +296,23 @@@ if (!dont_change_ref) { struct ref_transaction *transaction; struct strbuf err = STRBUF_INIT; + char *msg; + + if (forcing) + msg = xstrfmt("branch: Reset to %s", start_name); + else + msg = xstrfmt("branch: Created from %s", start_name); transaction = ref_transaction_begin(&err); if (!transaction || ref_transaction_update(transaction, ref.buf, - sha1, forcing ? NULL : null_sha1, + oid.hash, forcing ? NULL : null_sha1, 0, msg, &err) || ref_transaction_commit(transaction, &err)) die("%s", err.buf); ref_transaction_free(transaction); strbuf_release(&err); + free(msg); } if (real_ref && track) @@@ -357,8 -357,9 +357,9 @@@ int replace_each_worktree_head_symref(c if (worktrees[i]->is_detached) continue; - if (worktrees[i]->head_ref && - strcmp(oldref, worktrees[i]->head_ref)) + if (!worktrees[i]->head_ref) + continue; + if (strcmp(oldref, worktrees[i]->head_ref)) continue; refs = get_worktree_ref_store(worktrees[i]); diff --combined t/t3200-branch.sh index 51738fb969,c5c371888b..d971649979 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@@ -100,23 -100,6 +100,23 @@@ test_expect_success 'git branch -m n/n git reflog exists refs/heads/n ' +# The topmost entry in reflog for branch bbb is about branch creation. +# Hence, we compare bbb@{1} (instead of bbb@{0}) with aaa@{0}. + +test_expect_success 'git branch -m bbb should rename checked out branch' ' + test_when_finished git branch -D bbb && + test_when_finished git checkout master && + git checkout -b aaa && + git commit --allow-empty -m "a new commit" && + git rev-parse aaa@{0} >expect && + git branch -m bbb && + git rev-parse bbb@{1} >actual && + test_cmp expect actual && + git symbolic-ref HEAD >actual && + echo refs/heads/bbb >expect && + test_cmp expect actual +' + test_expect_success 'git branch -m o/o o should fail when o/p exists' ' git branch o/o && git branch o/p && @@@ -162,16 -145,19 +162,29 @@@ test_expect_success 'git branch -M baz grep "^0\{40\}.*$msg$" .git/logs/HEAD ' + test_expect_success 'git branch -M should leave orphaned HEAD alone' ' + git init orphan && + ( + cd orphan && + test_commit initial && + git checkout --orphan lonely && + grep lonely .git/HEAD && + test_path_is_missing .git/refs/head/lonely && + git branch -M master mistress && + grep lonely .git/HEAD + ) + ' + +test_expect_success 'resulting reflog can be shown by log -g' ' + oid=$(git rev-parse HEAD) && + cat >expect <<-EOF && + HEAD@{0} $oid $msg + HEAD@{2} $oid checkout: moving from foo to baz + EOF + git log -g --format="%gd %H %gs" -2 HEAD >actual && + test_cmp expect actual +' + test_expect_success 'git branch -M baz bam should succeed when baz is checked out as linked working tree' ' git checkout master && git worktree add -b baz bazdir && @@@ -365,7 -351,7 +378,7 @@@ test_expect_success 'git branch -m s/s test_expect_success 'config information was renamed, too' ' test $(git config branch.s.dummy) = Hello && - test_must_fail git config branch.s/s/dummy + test_must_fail git config branch.s/s.dummy ' test_expect_success 'deleting a symref' ' @@@ -559,7 -545,6 +572,7 @@@ test_expect_success 'use --set-upstream test_expect_success 'use --set-upstream-to modify a particular branch' ' git branch my13 && git branch --set-upstream-to master my13 && + test_when_finished "git branch --unset-upstream my13" && test "$(git config branch.my13.remote)" = "." && test "$(git config branch.my13.merge)" = "refs/heads/master" ' @@@ -605,8 -590,38 +618,8 @@@ test_expect_success 'test --unset-upstr test_must_fail git config branch.my14.merge ' -test_expect_success '--set-upstream shows message when creating a new branch that exists as remote-tracking' ' - git update-ref refs/remotes/origin/master HEAD && - git branch --set-upstream origin/master 2>actual && - test_when_finished git update-ref -d refs/remotes/origin/master && - test_when_finished git branch -d origin/master && - cat >expected <actual && - test_when_finished git branch --unset-upstream master && - cat >expected <actual && - test_when_finished git branch --unset-upstream my13 && - cat >expected <"$1" @@@ -963,10 -991,6 +976,10 @@@ test_expect_success '--merged catches i test_must_fail git branch --merged 0000000000000000000000000000000000000000 ' +test_expect_success '--merged is incompatible with --no-merged' ' + test_must_fail git branch --merged HEAD --no-merged HEAD +' + test_expect_success 'tracking with unexpected .fetch refspec' ' rm -rf a b c d && git init a && diff --combined worktree.c index e28ffbeb09,7bc36f4343..c0c5a2b373 --- a/worktree.c +++ b/worktree.c @@@ -1,5 -1,4 +1,5 @@@ #include "cache.h" +#include "repository.h" #include "refs.h" #include "strbuf.h" #include "worktree.h" @@@ -30,7 -29,7 +30,7 @@@ static void add_head_info(struct worktr target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt), "HEAD", - RESOLVE_REF_READING, + 0, wt->head_sha1, &flags); if (!target) return; @@@ -77,7 -76,7 +77,7 @@@ static struct worktree *get_linked_work if (!id) die("Missing linked worktree name"); - strbuf_git_common_path(&path, "worktrees/%s/gitdir", id); + strbuf_git_common_path(&path, the_repository, "worktrees/%s/gitdir", id); if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0) /* invalid gitdir file */ goto done; @@@ -210,19 -209,16 +210,19 @@@ struct worktree *find_worktree(struct w { struct worktree *wt; char *path; + char *to_free = NULL; if ((wt = find_worktree_by_suffix(list, arg))) return wt; - arg = prefix_filename(prefix, strlen(prefix), arg); + if (prefix) + arg = to_free = prefix_filename(prefix, arg); path = real_pathdup(arg, 1); for (; *list; list++) if (!fspathcmp(path, real_path((*list)->path))) break; free(path); + free(to_free); return *list; } @@@ -352,7 -348,6 +352,7 @@@ int submodule_uses_worktrees(const cha /* The env would be set for the superproject. */ get_common_dir_noenv(&sb, submodule_gitdir); + free(submodule_gitdir); /* * The check below is only known to be good for repository format @@@ -372,6 -367,7 +372,6 @@@ /* See if there is any file inside the worktrees directory. */ dir = opendir(sb.buf); strbuf_release(&sb); - free(submodule_gitdir); if (!dir) return 0;