Skip to content

Commit a3db851

Browse files
committed
Merge branch 'mm/simple-push'
New users tend to work on one branch at a time and push the result out. The current and upstream modes of push is a more suitable default mode than matching mode for these people, but neither is surprise-free depending on how the project is set up. Introduce a "simple" mode that is a subset of "upstream" but only works when the branch is named the same between the remote and local repositories. The plan is to make it the new default when push.default is not configured. By Matthieu Moy (5) and others * mm/simple-push: push.default doc: explain simple after upstream push: document the future default change for push.default (matching -> simple) t5570: use explicit push refspec push: introduce new push.default mode "simple" t5528-push-default.sh: add helper functions Undocument deprecated alias 'push.default=tracking' Documentation: explain push.default option a bit more
2 parents d4a5d87 + f4d80d2 commit a3db851

File tree

6 files changed

+157
-31
lines changed

6 files changed

+157
-31
lines changed

Documentation/config.txt

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,12 +1683,30 @@ push.default::
16831683
line. Possible values are:
16841684
+
16851685
* `nothing` - do not push anything.
1686-
* `matching` - push all matching branches.
1687-
All branches having the same name in both ends are considered to be
1688-
matching. This is the default.
1686+
* `matching` - push all branches having the same name in both ends.
1687+
This is for those who prepare all the branches into a publishable
1688+
shape and then push them out with a single command. It is not
1689+
appropriate for pushing into a repository shared by multiple users,
1690+
since locally stalled branches will attempt a non-fast forward push
1691+
if other users updated the branch.
1692+
+
1693+
This is currently the default, but Git 2.0 will change the default
1694+
to `simple`.
16891695
* `upstream` - push the current branch to its upstream branch.
1690-
* `tracking` - deprecated synonym for `upstream`.
1696+
With this, `git push` will update the same remote ref as the one which
1697+
is merged by `git pull`, making `push` and `pull` symmetrical.
1698+
See "branch.<name>.merge" for how to configure the upstream branch.
1699+
* `simple` - like `upstream`, but refuses to push if the upstream
1700+
branch's name is different from the local one. This is the safest
1701+
option and is well-suited for beginners. It will become the default
1702+
in Git 2.0.
16911703
* `current` - push the current branch to a branch of the same name.
1704+
+
1705+
The `simple`, `current` and `upstream` modes are for those who want to
1706+
push out a single branch after finishing work, even when the other
1707+
branches are not yet ready to be pushed out. If you are working with
1708+
other people to push into the same shared repository, you would want
1709+
to use one of these.
16921710

16931711
rebase.stat::
16941712
Whether to show a diffstat of what changed upstream since the last

builtin/push.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,44 @@ static int push_url_of_remote(struct remote *remote, const char ***url_p)
7676
return remote->url_nr;
7777
}
7878

79-
static void setup_push_upstream(struct remote *remote)
79+
static NORETURN int die_push_simple(struct branch *branch, struct remote *remote) {
80+
/*
81+
* There's no point in using shorten_unambiguous_ref here,
82+
* as the ambiguity would be on the remote side, not what
83+
* we have locally. Plus, this is supposed to be the simple
84+
* mode. If the user is doing something crazy like setting
85+
* upstream to a non-branch, we should probably be showing
86+
* them the big ugly fully qualified ref.
87+
*/
88+
const char *advice_maybe = "";
89+
const char *short_upstream =
90+
skip_prefix(branch->merge[0]->src, "refs/heads/");
91+
92+
if (!short_upstream)
93+
short_upstream = branch->merge[0]->src;
94+
/*
95+
* Don't show advice for people who explicitely set
96+
* push.default.
97+
*/
98+
if (push_default == PUSH_DEFAULT_UNSPECIFIED)
99+
advice_maybe = _("\n"
100+
"To choose either option permanently, "
101+
"see push.default in 'git help config'.");
102+
die(_("The upstream branch of your current branch does not match\n"
103+
"the name of your current branch. To push to the upstream branch\n"
104+
"on the remote, use\n"
105+
"\n"
106+
" git push %s HEAD:%s\n"
107+
"\n"
108+
"To push to the branch of the same name on the remote, use\n"
109+
"\n"
110+
" git push %s %s\n"
111+
"%s"),
112+
remote->name, short_upstream,
113+
remote->name, branch->name, advice_maybe);
114+
}
115+
116+
static void setup_push_upstream(struct remote *remote, int simple)
80117
{
81118
struct strbuf refspec = STRBUF_INIT;
82119
struct branch *branch = branch_get(NULL);
@@ -103,6 +140,8 @@ static void setup_push_upstream(struct remote *remote)
103140
"your current branch '%s', without telling me what to push\n"
104141
"to update which remote branch."),
105142
remote->name, branch->name);
143+
if (simple && strcmp(branch->refname, branch->merge[0]->src))
144+
die_push_simple(branch, remote);
106145

107146
strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
108147
add_refspec(refspec.buf);
@@ -119,8 +158,12 @@ static void setup_default_push_refspecs(struct remote *remote)
119158
add_refspec(":");
120159
break;
121160

161+
case PUSH_DEFAULT_SIMPLE:
162+
setup_push_upstream(remote, 1);
163+
break;
164+
122165
case PUSH_DEFAULT_UPSTREAM:
123-
setup_push_upstream(remote);
166+
setup_push_upstream(remote, 0);
124167
break;
125168

126169
case PUSH_DEFAULT_CURRENT:

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ enum rebase_setup_type {
580580
enum push_default_type {
581581
PUSH_DEFAULT_NOTHING = 0,
582582
PUSH_DEFAULT_MATCHING,
583+
PUSH_DEFAULT_SIMPLE,
583584
PUSH_DEFAULT_UPSTREAM,
584585
PUSH_DEFAULT_CURRENT,
585586
PUSH_DEFAULT_UNSPECIFIED

config.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,8 @@ static int git_default_push_config(const char *var, const char *value)
835835
push_default = PUSH_DEFAULT_NOTHING;
836836
else if (!strcmp(value, "matching"))
837837
push_default = PUSH_DEFAULT_MATCHING;
838+
else if (!strcmp(value, "simple"))
839+
push_default = PUSH_DEFAULT_SIMPLE;
838840
else if (!strcmp(value, "upstream"))
839841
push_default = PUSH_DEFAULT_UPSTREAM;
840842
else if (!strcmp(value, "tracking")) /* deprecated */
@@ -843,8 +845,8 @@ static int git_default_push_config(const char *var, const char *value)
843845
push_default = PUSH_DEFAULT_CURRENT;
844846
else {
845847
error("Malformed value for %s: %s", var, value);
846-
return error("Must be one of nothing, matching, "
847-
"tracking or current.");
848+
return error("Must be one of nothing, matching, simple, "
849+
"upstream or current.");
848850
}
849851
return 0;
850852
}

t/t5528-push-default.sh

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,44 @@ test_expect_success 'setup bare remotes' '
1313
git push parent2 HEAD
1414
'
1515

16+
# $1 = local revision
17+
# $2 = remote revision (tested to be equal to the local one)
18+
check_pushed_commit () {
19+
git log -1 --format='%h %s' "$1" >expect &&
20+
git --git-dir=repo1 log -1 --format='%h %s' "$2" >actual &&
21+
test_cmp expect actual
22+
}
23+
24+
# $1 = push.default value
25+
# $2 = expected target branch for the push
26+
test_push_success () {
27+
git -c push.default="$1" push &&
28+
check_pushed_commit HEAD "$2"
29+
}
30+
31+
# $1 = push.default value
32+
# check that push fails and does not modify any remote branch
33+
test_push_failure () {
34+
git --git-dir=repo1 log --no-walk --format='%h %s' --all >expect &&
35+
test_must_fail git -c push.default="$1" push &&
36+
git --git-dir=repo1 log --no-walk --format='%h %s' --all >actual &&
37+
test_cmp expect actual
38+
}
39+
1640
test_expect_success '"upstream" pushes to configured upstream' '
1741
git checkout master &&
1842
test_config branch.master.remote parent1 &&
1943
test_config branch.master.merge refs/heads/foo &&
20-
test_config push.default upstream &&
2144
test_commit two &&
22-
git push &&
23-
echo two >expect &&
24-
git --git-dir=repo1 log -1 --format=%s foo >actual &&
25-
test_cmp expect actual
45+
test_push_success upstream foo
2646
'
2747

2848
test_expect_success '"upstream" does not push on unconfigured remote' '
2949
git checkout master &&
3050
test_unconfig branch.master.remote &&
3151
test_config push.default upstream &&
3252
test_commit three &&
33-
test_must_fail git push
53+
test_push_failure upstream
3454
'
3555

3656
test_expect_success '"upstream" does not push on unconfigured branch' '
@@ -39,7 +59,7 @@ test_expect_success '"upstream" does not push on unconfigured branch' '
3959
test_unconfig branch.master.merge &&
4060
test_config push.default upstream
4161
test_commit four &&
42-
test_must_fail git push
62+
test_push_failure upstream
4363
'
4464

4565
test_expect_success '"upstream" does not push when remotes do not match' '
@@ -51,4 +71,48 @@ test_expect_success '"upstream" does not push when remotes do not match' '
5171
test_must_fail git push parent2
5272
'
5373

74+
test_expect_success 'push from/to new branch with upstream, matching and simple' '
75+
git checkout -b new-branch &&
76+
test_push_failure simple &&
77+
test_push_failure matching &&
78+
test_push_failure upstream
79+
'
80+
81+
test_expect_success 'push from/to new branch with current creates remote branch' '
82+
test_config branch.new-branch.remote repo1 &&
83+
git checkout new-branch &&
84+
test_push_success current new-branch
85+
'
86+
87+
test_expect_success 'push to existing branch, with no upstream configured' '
88+
test_config branch.master.remote repo1 &&
89+
git checkout master &&
90+
test_push_failure simple &&
91+
test_push_failure upstream
92+
'
93+
94+
test_expect_success 'push to existing branch, upstream configured with same name' '
95+
test_config branch.master.remote repo1 &&
96+
test_config branch.master.merge refs/heads/master &&
97+
git checkout master &&
98+
test_commit six &&
99+
test_push_success upstream master &&
100+
test_commit seven &&
101+
test_push_success simple master
102+
'
103+
104+
test_expect_success 'push to existing branch, upstream configured with different name' '
105+
test_config branch.master.remote repo1 &&
106+
test_config branch.master.merge refs/heads/other-name &&
107+
git checkout master &&
108+
test_commit eight &&
109+
test_push_success upstream other-name &&
110+
test_commit nine &&
111+
test_push_failure simple &&
112+
git --git-dir=repo1 log -1 --format="%h %s" "other-name" >expect-other-name &&
113+
test_push_success current master &&
114+
git --git-dir=repo1 log -1 --format="%h %s" "other-name" >actual-other-name &&
115+
test_cmp expect-other-name actual-other-name
116+
'
117+
54118
test_done

t/t5570-git-daemon.sh

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,12 @@ test_remote_error()
103103
esac
104104
done
105105

106-
if test $# -ne 3
107-
then
108-
error "invalid number of arguments"
109-
fi
110-
106+
msg=$1
107+
shift
111108
cmd=$1
112-
repo=$2
113-
msg=$3
109+
shift
110+
repo=$1
111+
shift || error "invalid number of arguments"
114112

115113
if test -x "$GIT_DAEMON_DOCUMENT_ROOT_PATH/$repo"
116114
then
@@ -122,7 +120,7 @@ test_remote_error()
122120
fi
123121
fi
124122

125-
test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" 2>output &&
123+
test_must_fail git "$cmd" "$GIT_DAEMON_URL/$repo" "$@" 2>output &&
126124
echo "fatal: remote error: $msg: /$repo" >expect &&
127125
test_cmp expect output
128126
ret=$?
@@ -131,18 +129,18 @@ test_remote_error()
131129
}
132130

133131
msg="access denied or repository not exported"
134-
test_expect_success 'clone non-existent' "test_remote_error clone nowhere.git '$msg'"
135-
test_expect_success 'push disabled' "test_remote_error push repo.git '$msg'"
136-
test_expect_success 'read access denied' "test_remote_error -x fetch repo.git '$msg'"
137-
test_expect_success 'not exported' "test_remote_error -n fetch repo.git '$msg'"
132+
test_expect_success 'clone non-existent' "test_remote_error '$msg' clone nowhere.git "
133+
test_expect_success 'push disabled' "test_remote_error '$msg' push repo.git master"
134+
test_expect_success 'read access denied' "test_remote_error -x '$msg' fetch repo.git "
135+
test_expect_success 'not exported' "test_remote_error -n '$msg' fetch repo.git "
138136

139137
stop_git_daemon
140138
start_git_daemon --informative-errors
141139

142-
test_expect_success 'clone non-existent' "test_remote_error clone nowhere.git 'no such repository'"
143-
test_expect_success 'push disabled' "test_remote_error push repo.git 'service not enabled'"
144-
test_expect_success 'read access denied' "test_remote_error -x fetch repo.git 'no such repository'"
145-
test_expect_success 'not exported' "test_remote_error -n fetch repo.git 'repository not exported'"
140+
test_expect_success 'clone non-existent' "test_remote_error 'no such repository' clone nowhere.git "
141+
test_expect_success 'push disabled' "test_remote_error 'service not enabled' push repo.git master"
142+
test_expect_success 'read access denied' "test_remote_error -x 'no such repository' fetch repo.git "
143+
test_expect_success 'not exported' "test_remote_error -n 'repository not exported' fetch repo.git "
146144

147145
stop_git_daemon
148146
test_done

0 commit comments

Comments
 (0)