From 6183d826ba62ec94ccfcb8f6e3b8d43e3e338703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 20 Aug 2012 15:47:38 +0200 Subject: [PATCH 1/3] branch: introduce --set-upstream-to MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing --set-uptream option can cause confusion, as it uses the usual branch convention of assuming a starting point of HEAD if none is specified, causing git branch --set-upstream origin/master to create a new local branch 'origin/master' that tracks the current branch. As --set-upstream already exists, we can't simply change its behaviour. To work around this, introduce --set-upstream-to which accepts a compulsory argument indicating what the new upstream branch should be and one optinal argument indicating which branch to change, defaulting to HEAD. The new options allows us to type git branch --set-upstream-to origin/master to set the current branch's upstream to be origin's master. Signed-off-by: Carlos Martín Nieto Signed-off-by: Junio C Hamano --- Documentation/git-branch.txt | 9 ++++++++- builtin/branch.c | 17 +++++++++++++++-- t/t3200-branch.sh | 14 ++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 47235bea04..e41c4b55fd 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -13,6 +13,7 @@ SYNOPSIS [--column[=] | --no-column] [(--merged | --no-merged | --contains) []] [...] 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] [] +'git branch' (--set-upstream-to= | -u ) [] 'git branch' (-m | -M) [] 'git branch' (-d | -D) [-r] ... 'git branch' --edit-description [] @@ -48,7 +49,7 @@ branch so that 'git pull' will appropriately merge from the remote-tracking branch. This behavior may be changed via the global `branch.autosetupmerge` configuration flag. That setting can be overridden by using the `--track` and `--no-track` options, and -changed later using `git branch --set-upstream`. +changed later using `git branch --set-upstream-to`. With a `-m` or `-M` option, will be renamed to . If had a corresponding reflog, it is renamed to match @@ -173,6 +174,12 @@ start-point is either a local or remote-tracking branch. like `--track` would when creating the branch, except that where branch points to is not changed. +-u :: +--set-upstream-to=:: + Set up 's tracking information so is + considered 's upstream branch. If no + is specified, then it defaults to the current branch. + --edit-description:: Open an editor and edit the text to explain what the branch is for, to be used by various other commands (e.g. `request-pull`). diff --git a/builtin/branch.c b/builtin/branch.c index 0e060f2e4a..3c978eb18e 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -713,6 +713,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) int verbose = 0, abbrev = -1, detached = 0; int reflog = 0, edit_description = 0; int quiet = 0; + const char *new_upstream = NULL; enum branch_track track; int kinds = REF_LOCAL_BRANCH; struct commit_list *with_commit = NULL; @@ -726,6 +727,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) BRANCH_TRACK_EXPLICIT), OPT_SET_INT( 0, "set-upstream", &track, "change upstream info", BRANCH_TRACK_OVERRIDE), + OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"), OPT__COLOR(&branch_use_color, "use colored output"), OPT_SET_INT('r', "remotes", &kinds, "act on remote-tracking branches", REF_REMOTE_BRANCH), @@ -794,10 +796,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, builtin_branch_usage, 0); - if (!delete && !rename && !edit_description && argc == 0) + if (!delete && !rename && !edit_description && !new_upstream && argc == 0) list = 1; - if (!!delete + !!rename + !!force_create + !!list > 1) + if (!!delete + !!rename + !!force_create + !!list + !!new_upstream > 1) usage_with_options(builtin_branch_usage, options); if (abbrev == -1) @@ -852,6 +854,17 @@ int cmd_branch(int argc, const char **argv, const char *prefix) rename_branch(argv[0], argv[1], rename > 1); else usage_with_options(builtin_branch_usage, options); + } else if (new_upstream) { + struct branch *branch = branch_get(argv[0]); + + if (!ref_exists(branch->refname)) + die(_("branch '%s' does not exist"), branch->name); + + /* + * create_branch takes care of setting up the tracking + * info and making sure new_upstream is correct + */ + create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE); } else if (argc > 0 && argc <= 2) { if (kinds != REF_LOCAL_BRANCH) die(_("-a and -r options to 'git branch' do not make sense with a branch name")); diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index a17f8b2a40..e9019ac943 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -369,6 +369,20 @@ test_expect_success \ 'git tag foobar && test_must_fail git branch --track my11 foobar' +test_expect_success 'use --set-upstream-to modify HEAD' \ + 'test_config branch.master.remote foo && + test_config branch.master.merge foo && + git branch my12 + git branch --set-upstream-to my12 && + test "$(git config branch.master.remote)" = "." && + test "$(git config branch.master.merge)" = "refs/heads/my12"' + +test_expect_success 'use --set-upstream-to modify a particular branch' \ + 'git branch my13 + git branch --set-upstream-to master my13 && + test "$(git config branch.my13.remote)" = "." && + test "$(git config branch.my13.merge)" = "refs/heads/master"' + # Keep this test last, as it changes the current branch cat >expect < 1117150200 +0000 branch: Created from master From b84869ef14081b298a4ab825219221ccfcb2a3ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 30 Aug 2012 19:23:12 +0200 Subject: [PATCH 2/3] branch: add --unset-upstream option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have ways of setting the upstream information, but if we want to unset it, we need to resort to modifying the configuration manually. Teach branch an --unset-upstream option that unsets this information. Signed-off-by: Carlos Martín Nieto Signed-off-by: Junio C Hamano --- Documentation/git-branch.txt | 5 +++++ builtin/branch.c | 21 ++++++++++++++++++--- t/t3200-branch.sh | 22 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index e41c4b55fd..9c1d2f1781 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -14,6 +14,7 @@ SYNOPSIS [(--merged | --no-merged | --contains) []] [...] 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] [] 'git branch' (--set-upstream-to= | -u ) [] +'git branch' --unset-upstream [] 'git branch' (-m | -M) [] 'git branch' (-d | -D) [-r] ... 'git branch' --edit-description [] @@ -180,6 +181,10 @@ start-point is either a local or remote-tracking branch. considered 's upstream branch. If no is specified, then it defaults to the current branch. +--unset-upstream:: + Remove the upstream information for . If no branch + is specified it defaults to the current branch. + --edit-description:: Open an editor and edit the text to explain what the branch is for, to be used by various other commands (e.g. `request-pull`). diff --git a/builtin/branch.c b/builtin/branch.c index 3c978eb18e..557995d978 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -712,7 +712,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) int delete = 0, rename = 0, force_create = 0, list = 0; int verbose = 0, abbrev = -1, detached = 0; int reflog = 0, edit_description = 0; - int quiet = 0; + int quiet = 0, unset_upstream = 0; const char *new_upstream = NULL; enum branch_track track; int kinds = REF_LOCAL_BRANCH; @@ -728,6 +728,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_SET_INT( 0, "set-upstream", &track, "change upstream info", BRANCH_TRACK_OVERRIDE), OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"), + OPT_BOOLEAN(0, "unset-upstream", &unset_upstream, "Unset the upstream info"), OPT__COLOR(&branch_use_color, "use colored output"), OPT_SET_INT('r', "remotes", &kinds, "act on remote-tracking branches", REF_REMOTE_BRANCH), @@ -796,10 +797,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, builtin_branch_usage, 0); - if (!delete && !rename && !edit_description && !new_upstream && argc == 0) + if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0) list = 1; - if (!!delete + !!rename + !!force_create + !!list + !!new_upstream > 1) + if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1) usage_with_options(builtin_branch_usage, options); if (abbrev == -1) @@ -865,6 +866,20 @@ int cmd_branch(int argc, const char **argv, const char *prefix) * info and making sure new_upstream is correct */ create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE); + } else if (unset_upstream) { + struct branch *branch = branch_get(argv[0]); + struct strbuf buf = STRBUF_INIT; + + if (!branch_has_merge_config(branch)) { + die(_("Branch '%s' has no upstream information"), branch->name); + } + + strbuf_addf(&buf, "branch.%s.remote", branch->name); + git_config_set_multivar(buf.buf, NULL, NULL, 1); + strbuf_reset(&buf); + strbuf_addf(&buf, "branch.%s.merge", branch->name); + git_config_set_multivar(buf.buf, NULL, NULL, 1); + strbuf_release(&buf); } else if (argc > 0 && argc <= 2) { if (kinds != REF_LOCAL_BRANCH) die(_("-a and -r options to 'git branch' do not make sense with a branch name")); diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index e9019ac943..0bf72d2067 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -383,6 +383,28 @@ test_expect_success 'use --set-upstream-to modify a particular branch' \ test "$(git config branch.my13.remote)" = "." && test "$(git config branch.my13.merge)" = "refs/heads/master"' +test_expect_success '--unset-upstream should fail if given a non-existent branch' \ + 'test_must_fail git branch --unset-upstream i-dont-exist' + +test_expect_success 'test --unset-upstream on HEAD' \ + 'git branch my14 + test_config branch.master.remote foo && + test_config branch.master.merge foo && + git branch --set-upstream-to my14 && + git branch --unset-upstream && + test_must_fail git config branch.master.remote && + test_must_fail git config branch.master.merge && + # fail for a branch without upstream set + test_must_fail git branch --unset-upstream +' + +test_expect_success 'test --unset-upstream on a particular branch' \ + 'git branch my15 + git branch --set-upstream-to master my14 && + git branch --unset-upstream my14 && + test_must_fail git config branch.my14.remote && + test_must_fail git config branch.my14.merge' + # Keep this test last, as it changes the current branch cat >expect < 1117150200 +0000 branch: Created from master From b347d06bf097aca5effd07871adf4d0c8a7c55bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 30 Aug 2012 19:23:13 +0200 Subject: [PATCH 3/3] branch: deprecate --set-upstream and show help if we detect possible mistaken use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This interface is error prone, and a better one (--set-upstream-to) exists. Add a message listing the alternatives and suggest how to fix a --set-upstream invocation in case the user only gives one argument which causes a local branch with the same name as a remote-tracking one to be created. The typical case is git branch --set-upstream origin/master when the user meant git branch --set-upstream master origin/master assuming that the current branch is master. Show a message telling the user how to undo their action and get what they wanted. For the command above, the message would be The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to Branch origin/master set up to track local branch master. If you wanted to make 'master' track 'origin/master', do this: git branch -d origin/master git branch --set-upstream-to origin/master Signed-off-by: Carlos Martín Nieto Signed-off-by: Junio C Hamano --- builtin/branch.c | 26 ++++++++++++++++++++++++++ t/t3200-branch.sh | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/builtin/branch.c b/builtin/branch.c index 557995d978..5e95e3568a 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -881,10 +881,36 @@ int cmd_branch(int argc, const char **argv, const char *prefix) git_config_set_multivar(buf.buf, NULL, NULL, 1); strbuf_release(&buf); } else if (argc > 0 && argc <= 2) { + struct branch *branch = branch_get(argv[0]); + int branch_existed = 0, remote_tracking = 0; + struct strbuf buf = STRBUF_INIT; + if (kinds != REF_LOCAL_BRANCH) die(_("-a and -r options to 'git branch' do not make sense with a branch name")); + + if (track == BRANCH_TRACK_OVERRIDE) + fprintf(stderr, _("The --set-upstream flag is deprecated and will be removed. Consider using --track or --set-upstream-to\n")); + + strbuf_addf(&buf, "refs/remotes/%s", branch->name); + remote_tracking = ref_exists(buf.buf); + strbuf_release(&buf); + + branch_existed = ref_exists(branch->refname); create_branch(head, argv[0], (argc == 2) ? argv[1] : head, force_create, reflog, 0, quiet, track); + + /* + * We only show the instructions if the user gave us + * one branch which doesn't exist locally, but is the + * name of a remote-tracking branch. + */ + if (argc == 1 && track == BRANCH_TRACK_OVERRIDE && + !branch_existed && remote_tracking) { + fprintf(stderr, _("\nIf you wanted to make '%s' track '%s', do this:\n\n"), head, branch->name); + fprintf(stderr, _(" git branch -d %s\n"), branch->name); + fprintf(stderr, _(" git branch --set-upstream-to %s\n"), branch->name); + } + } else usage_with_options(builtin_branch_usage, options); diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 0bf72d2067..2a54a76abb 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -405,6 +405,40 @@ test_expect_success 'test --unset-upstream on a particular branch' \ test_must_fail git config branch.my14.remote && 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 <expect < 1117150200 +0000 branch: Created from master