Merge branch 'cn/branch-set-upstream-to'

"git branch --set-upstream origin/master" is a common mistake to
create a local branch 'origin/master' and set it to integrate with
the current branch.  With a plan to deprecate this option, introduce
"git branch (-u|--set-upstream-to) origin/master" that sets the
current branch to integrate with 'origin/master' remote tracking
branch.

* cn/branch-set-upstream-to:
  branch: deprecate --set-upstream and show help if we detect possible mistaken use
  branch: add --unset-upstream option
  branch: introduce --set-upstream-to
This commit is contained in:
Junio C Hamano 2012-09-10 15:43:07 -07:00
commit 83ce176449
3 changed files with 140 additions and 4 deletions

View file

@ -13,6 +13,8 @@ SYNOPSIS
[--column[=<options>] | --no-column] [--column[=<options>] | --no-column]
[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...] [(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>] 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
'git branch' --unset-upstream [<branchname>]
'git branch' (-m | -M) [<oldbranch>] <newbranch> 'git branch' (-m | -M) [<oldbranch>] <newbranch>
'git branch' (-d | -D) [-r] <branchname>... 'git branch' (-d | -D) [-r] <branchname>...
'git branch' --edit-description [<branchname>] 'git branch' --edit-description [<branchname>]
@ -48,7 +50,7 @@ branch so that 'git pull' will appropriately merge from
the remote-tracking branch. This behavior may be changed via the global the remote-tracking branch. This behavior may be changed via the global
`branch.autosetupmerge` configuration flag. That setting can be `branch.autosetupmerge` configuration flag. That setting can be
overridden by using the `--track` and `--no-track` options, and 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, <oldbranch> will be renamed to <newbranch>. With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>.
If <oldbranch> had a corresponding reflog, it is renamed to match If <oldbranch> had a corresponding reflog, it is renamed to match
@ -173,6 +175,16 @@ start-point is either a local or remote-tracking branch.
like `--track` would when creating the branch, except that where like `--track` would when creating the branch, except that where
branch points to is not changed. branch points to is not changed.
-u <upstream>::
--set-upstream-to=<upstream>::
Set up <branchname>'s tracking information so <upstream> is
considered <branchname>'s upstream branch. If no <branchname>
is specified, then it defaults to the current branch.
--unset-upstream::
Remove the upstream information for <branchname>. If no branch
is specified it defaults to the current branch.
--edit-description:: --edit-description::
Open an editor and edit the text to explain what the branch is 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`). for, to be used by various other commands (e.g. `request-pull`).

View file

@ -714,7 +714,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int delete = 0, rename = 0, force_create = 0, list = 0; int delete = 0, rename = 0, force_create = 0, list = 0;
int verbose = 0, abbrev = -1, detached = 0; int verbose = 0, abbrev = -1, detached = 0;
int reflog = 0, edit_description = 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; enum branch_track track;
int kinds = REF_LOCAL_BRANCH; int kinds = REF_LOCAL_BRANCH;
struct commit_list *with_commit = NULL; struct commit_list *with_commit = NULL;
@ -728,6 +729,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
BRANCH_TRACK_EXPLICIT), BRANCH_TRACK_EXPLICIT),
OPT_SET_INT( 0, "set-upstream", &track, N_("change upstream info"), OPT_SET_INT( 0, "set-upstream", &track, N_("change upstream info"),
BRANCH_TRACK_OVERRIDE), 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, N_("use colored output")), OPT__COLOR(&branch_use_color, N_("use colored output")),
OPT_SET_INT('r', "remotes", &kinds, N_("act on remote-tracking branches"), OPT_SET_INT('r', "remotes", &kinds, N_("act on remote-tracking branches"),
REF_REMOTE_BRANCH), REF_REMOTE_BRANCH),
@ -796,10 +799,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, options, builtin_branch_usage, argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
0); 0);
if (!delete && !rename && !edit_description && argc == 0) if (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)
list = 1; list = 1;
if (!!delete + !!rename + !!force_create + !!list > 1) if (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)
usage_with_options(builtin_branch_usage, options); usage_with_options(builtin_branch_usage, options);
if (abbrev == -1) if (abbrev == -1)
@ -854,11 +857,62 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
rename_branch(argv[0], argv[1], rename > 1); rename_branch(argv[0], argv[1], rename > 1);
else else
usage_with_options(builtin_branch_usage, options); 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 (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) { } 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) if (kinds != REF_LOCAL_BRANCH)
die(_("-a and -r options to 'git branch' do not make sense with a branch name")); 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, create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
force_create, reflog, 0, quiet, track); 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 } else
usage_with_options(builtin_branch_usage, options); usage_with_options(builtin_branch_usage, options);

View file

@ -369,6 +369,76 @@ test_expect_success \
'git tag foobar && 'git tag foobar &&
test_must_fail git branch --track my11 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"'
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'
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_cmp 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_cmp 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_cmp expected actual
'
# Keep this test last, as it changes the current branch # Keep this test last, as it changes the current branch
cat >expect <<EOF cat >expect <<EOF
$_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master $_z40 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master