OSDN Git Service

Merge branch 'nd/worktree-kill-parse-ref'
authorJunio C Hamano <gitster@pobox.com>
Sun, 10 Sep 2017 08:08:23 +0000 (17:08 +0900)
committerJunio C Hamano <gitster@pobox.com>
Sun, 10 Sep 2017 08:08:24 +0000 (17:08 +0900)
"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

1  2 
branch.c
t/t3200-branch.sh
worktree.c

diff --combined 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;
        }
  
        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);
                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)
                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;
        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
@@@ -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 <<EOF &&
 -The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
 -
 -If you wanted to make '"'master'"' track '"'origin/master'"', do this:
 -
 -    git branch -d origin/master
 -    git branch --set-upstream-to origin/master
 -EOF
 -      test_i18ncmp expected actual
 -'
 -
 -test_expect_success '--set-upstream with two args only shows the deprecation message' '
 -      git branch --set-upstream master my13 2>actual &&
 -      test_when_finished git branch --unset-upstream master &&
 -      cat >expected <<EOF &&
 -The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
 -EOF
 -      test_i18ncmp expected actual
 -'
 -
 -test_expect_success '--set-upstream with one arg only shows the deprecation message if the branch existed' '
 -      git branch --set-upstream my13 2>actual &&
 -      test_when_finished git branch --unset-upstream my13 &&
 -      cat >expected <<EOF &&
 -The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to
 -EOF
 -      test_i18ncmp expected actual
 +test_expect_success '--set-upstream fails' '
 +    test_must_fail git branch --set-upstream origin/master
  '
  
  test_expect_success '--set-upstream-to notices an error to set branch as own upstream' '
@@@ -931,6 -946,19 +944,6 @@@ test_expect_success 'attempt to delete 
        test_must_fail git branch -d my10
  '
  
 -test_expect_success 'use set-upstream on the current branch' '
 -      git checkout master &&
 -      git --bare init myupstream.git &&
 -      git push myupstream.git master:refs/heads/frotz &&
 -      git remote add origin myupstream.git &&
 -      git fetch &&
 -      git branch --set-upstream master origin/frotz &&
 -
 -      test "z$(git config branch.master.remote)" = "zorigin" &&
 -      test "z$(git config branch.master.merge)" = "zrefs/heads/frotz"
 -
 -'
 -
  test_expect_success 'use --edit-description' '
        write_script editor <<-\EOF &&
                echo "New contents" >"$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
@@@ -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
        /* See if there is any file inside the worktrees directory. */
        dir = opendir(sb.buf);
        strbuf_release(&sb);
 -      free(submodule_gitdir);
  
        if (!dir)
                return 0;