branch: introduce --set-upstream-to

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 <cmn@elego.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Carlos Martín Nieto committed Aug 20, 2012 at 15:47 UTC 6183d826ba62ec94ccfcb8f6e3b8d43e3e338703
3 files changed +37 -3
Documentation/git-branch.txt
+8 -1
@@ -13,6 +13,7 @@ SYNOPSIS
13 [--column[=<options>] | --no-column]
14 [(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
15 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
16 +'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
17 'git branch' (-m | -M) [<oldbranch>] <newbranch>
18 'git branch' (-d | -D) [-r] <branchname>...
19 'git branch' --edit-description [<branchname>]
@@ -48,7 +49,7 @@ branch so that 'git pull' will appropriately merge from
49 the remote-tracking branch. This behavior may be changed via the global
50 `branch.autosetupmerge` configuration flag. That setting can be
51 overridden by using the `--track` and `--no-track` options, and
51 -changed later using `git branch --set-upstream`.
52 +changed later using `git branch --set-upstream-to`.
53
54 With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>.
55 If <oldbranch> had a corresponding reflog, it is renamed to match
@@ -173,6 +174,12 @@ start-point is either a local or remote-tracking branch.
174 like `--track` would when creating the branch, except that where
175 branch points to is not changed.
176
177 +-u <upstream>::
178 +--set-upstream-to=<upstream>::
179 + Set up <branchname>'s tracking information so <upstream> is
180 + considered <branchname>'s upstream branch. If no <branchname>
181 + is specified, then it defaults to the current branch.
182 +
183 --edit-description::
184 Open an editor and edit the text to explain what the branch is
185 for, to be used by various other commands (e.g. `request-pull`).
builtin/branch.c
+15 -2
@@ -713,6 +713,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
713 int verbose = 0, abbrev = -1, detached = 0;
714 int reflog = 0, edit_description = 0;
715 int quiet = 0;
716 + const char *new_upstream = NULL;
717 enum branch_track track;
718 int kinds = REF_LOCAL_BRANCH;
719 struct commit_list *with_commit = NULL;
@@ -726,6 +727,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
727 BRANCH_TRACK_EXPLICIT),
728 OPT_SET_INT( 0, "set-upstream", &track, "change upstream info",
729 BRANCH_TRACK_OVERRIDE),
730 + OPT_STRING('u', "set-upstream-to", &new_upstream, "upstream", "change the upstream info"),
731 OPT__COLOR(&branch_use_color, "use colored output"),
732 OPT_SET_INT('r', "remotes", &kinds, "act on remote-tracking branches",
733 REF_REMOTE_BRANCH),
@@ -794,10 +796,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
796 argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
797 0);
798
797 - if (!delete && !rename && !edit_description && argc == 0)
799 + if (!delete && !rename && !edit_description && !new_upstream && argc == 0)
800 list = 1;
801
800 - if (!!delete + !!rename + !!force_create + !!list > 1)
802 + if (!!delete + !!rename + !!force_create + !!list + !!new_upstream > 1)
803 usage_with_options(builtin_branch_usage, options);
804
805 if (abbrev == -1)
@@ -852,6 +854,17 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
854 rename_branch(argv[0], argv[1], rename > 1);
855 else
856 usage_with_options(builtin_branch_usage, options);
857 + } else if (new_upstream) {
858 + struct branch *branch = branch_get(argv[0]);
859 +
860 + if (!ref_exists(branch->refname))
861 + die(_("branch '%s' does not exist"), branch->name);
862 +
863 + /*
864 + * create_branch takes care of setting up the tracking
865 + * info and making sure new_upstream is correct
866 + */
867 + create_branch(head, branch->name, new_upstream, 0, 0, 0, quiet, BRANCH_TRACK_OVERRIDE);
868 } else if (argc > 0 && argc <= 2) {
869 if (kinds != REF_LOCAL_BRANCH)
870 die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
t/t3200-branch.sh
+14
@@ -369,6 +369,20 @@ test_expect_success \
369 'git tag foobar &&
370 test_must_fail git branch --track my11 foobar'
371
372 +test_expect_success 'use --set-upstream-to modify HEAD' \
373 + 'test_config branch.master.remote foo &&
374 + test_config branch.master.merge foo &&
375 + git branch my12
376 + git branch --set-upstream-to my12 &&
377 + test "$(git config branch.master.remote)" = "." &&
378 + test "$(git config branch.master.merge)" = "refs/heads/my12"'
379 +
380 +test_expect_success 'use --set-upstream-to modify a particular branch' \
381 + 'git branch my13
382 + git branch --set-upstream-to master my13 &&
383 + test "$(git config branch.my13.remote)" = "." &&
384 + test "$(git config branch.my13.merge)" = "refs/heads/master"'
385 +
386 # Keep this test last, as it changes the current branch
387 cat >expect <<EOF
388 $_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master