Skip to content

Commit 3b8d276

Browse files
committed
Merge branch 'jc/triangle-push-fixup'
Earlier remote.pushdefault (and per-branch branch.*.pushremote) were introduced as an additional mechanism to choose what repository to push into when "git push" did not say it from the command line, to help people who push to a repository that is different from where they fetch from. This attempts to finish that topic by teaching the default mechanism to choose branch in the remote repository to be updated by such a push. The 'current', 'matching' and 'nothing' modes (specified by the push.default configuration variable) extend to such a "triangular" workflow naturally, but 'upstream' and 'simple' have to be updated. . 'upstream' is about pushing back to update the branch in the remote repository that the current branch fetches from and integrates with, it errors out in a triangular workflow. . 'simple' is meant to help new people by avoiding mistakes, and will be the safe default in Git 2.0. In a non-triangular workflow, it will continue to act as a cross between 'upstream' and 'current' in that it pushes to the current branch's @{upstream} only when it is set to the same name as the current branch (e.g. your 'master' forks from the 'master' from the central repository). In a triangular workflow, this series tentatively defines it as the same as 'current', but we may have to tighten it to avoid surprises in some way. * jc/triangle-push-fixup: t/t5528-push-default: test pushdefault workflows t/t5528-push-default: generalize test_push_* push: change `simple` to accommodate triangular workflows config doc: rewrite push.default section t/t5528-push-default: remove redundant test_config lines
2 parents fb58544 + 6e1696b commit 3b8d276

File tree

3 files changed

+142
-46
lines changed

3 files changed

+142
-46
lines changed

Documentation/config.txt

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,39 +1844,59 @@ pull.twohead::
18441844
The default merge strategy to use when pulling a single branch.
18451845

18461846
push.default::
1847-
Defines the action `git push` should take if no refspec is given
1848-
on the command line, no refspec is configured in the remote, and
1849-
no refspec is implied by any of the options given on the command
1850-
line. Possible values are:
1847+
Defines the action `git push` should take if no refspec is
1848+
explicitly given. Different values are well-suited for
1849+
specific workflows; for instance, in a purely central workflow
1850+
(i.e. the fetch source is equal to the push destination),
1851+
`upstream` is probably what you want. Possible values are:
18511852
+
18521853
--
1853-
* `nothing` - do not push anything.
1854-
* `matching` - push all branches having the same name in both ends.
1855-
This is for those who prepare all the branches into a publishable
1856-
shape and then push them out with a single command. It is not
1857-
appropriate for pushing into a repository shared by multiple users,
1858-
since locally stalled branches will attempt a non-fast forward push
1859-
if other users updated the branch.
1860-
+
1861-
This is currently the default, but Git 2.0 will change the default
1862-
to `simple`.
1863-
* `upstream` - push the current branch to its upstream branch
1864-
(`tracking` is a deprecated synonym for this).
1865-
With this, `git push` will update the same remote ref as the one which
1866-
is merged by `git pull`, making `push` and `pull` symmetrical.
1867-
See "branch.<name>.merge" for how to configure the upstream branch.
1868-
* `simple` - like `upstream`, but refuses to push if the upstream
1869-
branch's name is different from the local one. This is the safest
1870-
option and is well-suited for beginners. It will become the default
1871-
in Git 2.0.
1872-
* `current` - push the current branch to a branch of the same name.
1873-
--
1854+
1855+
* `nothing` - do not push anything (error out) unless a refspec is
1856+
explicitly given. This is primarily meant for people who want to
1857+
avoid mistakes by always being explicit.
1858+
1859+
* `current` - push the current branch to update a branch with the same
1860+
name on the receiving end. Works in both central and non-central
1861+
workflows.
1862+
1863+
* `upstream` - push the current branch back to the branch whose
1864+
changes are usually integrated into the current branch (which is
1865+
called `@{upstream}`). This mode only makes sense if you are
1866+
pushing to the same repository you would normally pull from
1867+
(i.e. central workflow).
1868+
1869+
* `simple` - in centralized workflow, work like `upstream` with an
1870+
added safety to refuse to push if the upstream branch's name is
1871+
different from the local one.
18741872
+
1875-
The `simple`, `current` and `upstream` modes are for those who want to
1876-
push out a single branch after finishing work, even when the other
1877-
branches are not yet ready to be pushed out. If you are working with
1878-
other people to push into the same shared repository, you would want
1879-
to use one of these.
1873+
When pushing to a remote that is different from the remote you normally
1874+
pull from, work as `current`. This is the safest option and is suited
1875+
for beginners.
1876+
+
1877+
This mode will become the default in Git 2.0.
1878+
1879+
* `matching` - push all branches having the same name on both ends.
1880+
This makes the repository you are pushing to remember the set of
1881+
branches that will be pushed out (e.g. if you always push 'maint'
1882+
and 'master' there and no other branches, the repository you push
1883+
to will have these two branches, and your local 'maint' and
1884+
'master' will be pushed there).
1885+
+
1886+
To use this mode effectively, you have to make sure _all_ the
1887+
branches you would push out are ready to be pushed out before
1888+
running 'git push', as the whole point of this mode is to allow you
1889+
to push all of the branches in one go. If you usually finish work
1890+
on only one branch and push out the result, while other branches are
1891+
unfinished, this mode is not for you. Also this mode is not
1892+
suitable for pushing into a shared central repository, as other
1893+
people may add new branches there, or update the tip of existing
1894+
branches outside your control.
1895+
+
1896+
This is currently the default, but Git 2.0 will change the default
1897+
to `simple`.
1898+
1899+
--
18801900

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

builtin/push.c

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,11 @@ static const char message_detached_head_die[] =
120120
"\n"
121121
" git push %s HEAD:<name-of-remote-branch>\n");
122122

123-
static void setup_push_upstream(struct remote *remote, int simple)
123+
static void setup_push_upstream(struct remote *remote, struct branch *branch,
124+
int triangular)
124125
{
125126
struct strbuf refspec = STRBUF_INIT;
126-
struct branch *branch = branch_get(NULL);
127+
127128
if (!branch)
128129
die(_(message_detached_head_die), remote->name);
129130
if (!branch->merge_nr || !branch->merge || !branch->remote_name)
@@ -137,18 +138,29 @@ static void setup_push_upstream(struct remote *remote, int simple)
137138
if (branch->merge_nr != 1)
138139
die(_("The current branch %s has multiple upstream branches, "
139140
"refusing to push."), branch->name);
140-
if (strcmp(branch->remote_name, remote->name))
141+
if (triangular)
141142
die(_("You are pushing to remote '%s', which is not the upstream of\n"
142143
"your current branch '%s', without telling me what to push\n"
143144
"to update which remote branch."),
144145
remote->name, branch->name);
145-
if (simple && strcmp(branch->refname, branch->merge[0]->src))
146-
die_push_simple(branch, remote);
146+
147+
if (push_default == PUSH_DEFAULT_SIMPLE) {
148+
/* Additional safety */
149+
if (strcmp(branch->refname, branch->merge[0]->src))
150+
die_push_simple(branch, remote);
151+
}
147152

148153
strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
149154
add_refspec(refspec.buf);
150155
}
151156

157+
static void setup_push_current(struct remote *remote, struct branch *branch)
158+
{
159+
if (!branch)
160+
die(_(message_detached_head_die), remote->name);
161+
add_refspec(branch->name);
162+
}
163+
152164
static char warn_unspecified_push_default_msg[] =
153165
N_("push.default is unset; its implicit value is changing in\n"
154166
"Git 2.0 from 'matching' to 'simple'. To squelch this message\n"
@@ -173,9 +185,16 @@ static void warn_unspecified_push_default_configuration(void)
173185
warning("%s\n", _(warn_unspecified_push_default_msg));
174186
}
175187

188+
static int is_workflow_triangular(struct remote *remote)
189+
{
190+
struct remote *fetch_remote = remote_get(NULL);
191+
return (fetch_remote && fetch_remote != remote);
192+
}
193+
176194
static void setup_default_push_refspecs(struct remote *remote)
177195
{
178-
struct branch *branch;
196+
struct branch *branch = branch_get(NULL);
197+
int triangular = is_workflow_triangular(remote);
179198

180199
switch (push_default) {
181200
default:
@@ -188,18 +207,18 @@ static void setup_default_push_refspecs(struct remote *remote)
188207
break;
189208

190209
case PUSH_DEFAULT_SIMPLE:
191-
setup_push_upstream(remote, 1);
210+
if (triangular)
211+
setup_push_current(remote, branch);
212+
else
213+
setup_push_upstream(remote, branch, triangular);
192214
break;
193215

194216
case PUSH_DEFAULT_UPSTREAM:
195-
setup_push_upstream(remote, 0);
217+
setup_push_upstream(remote, branch, triangular);
196218
break;
197219

198220
case PUSH_DEFAULT_CURRENT:
199-
branch = branch_get(NULL);
200-
if (!branch)
201-
die(_(message_detached_head_die), remote->name);
202-
add_refspec(branch->name);
221+
setup_push_current(remote, branch);
203222
break;
204223

205224
case PUSH_DEFAULT_NOTHING:

t/t5528-push-default.sh

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@ test_expect_success 'setup bare remotes' '
1515

1616
# $1 = local revision
1717
# $2 = remote revision (tested to be equal to the local one)
18+
# $3 = [optional] repo to check for actual output (repo1 by default)
1819
check_pushed_commit () {
1920
git log -1 --format='%h %s' "$1" >expect &&
20-
git --git-dir=repo1 log -1 --format='%h %s' "$2" >actual &&
21+
git --git-dir="${3:-repo1}" log -1 --format='%h %s' "$2" >actual &&
2122
test_cmp expect actual
2223
}
2324

2425
# $1 = push.default value
2526
# $2 = expected target branch for the push
27+
# $3 = [optional] repo to check for actual output (repo1 by default)
2628
test_push_success () {
2729
git -c push.default="$1" push &&
28-
check_pushed_commit HEAD "$2"
30+
check_pushed_commit HEAD "$2" "$3"
2931
}
3032

3133
# $1 = push.default value
@@ -37,6 +39,26 @@ test_push_failure () {
3739
test_cmp expect actual
3840
}
3941

42+
# $1 = success or failure
43+
# $2 = push.default value
44+
# $3 = branch to check for actual output (master or foo)
45+
# $4 = [optional] switch to triangular workflow
46+
test_pushdefault_workflow () {
47+
workflow=central
48+
pushdefault=parent1
49+
if test -n "${4-}"; then
50+
workflow=triangular
51+
pushdefault=parent2
52+
fi
53+
test_expect_success "push.default = $2 $1 in $workflow workflows" "
54+
test_config branch.master.remote parent1 &&
55+
test_config branch.master.merge refs/heads/foo &&
56+
test_config remote.pushdefault $pushdefault &&
57+
test_commit commit-for-$2${4+-triangular} &&
58+
test_push_$1 $2 $3 ${4+repo2}
59+
"
60+
}
61+
4062
test_expect_success '"upstream" pushes to configured upstream' '
4163
git checkout master &&
4264
test_config branch.master.remote parent1 &&
@@ -48,7 +70,6 @@ test_expect_success '"upstream" pushes to configured upstream' '
4870
test_expect_success '"upstream" does not push on unconfigured remote' '
4971
git checkout master &&
5072
test_unconfig branch.master.remote &&
51-
test_config push.default upstream &&
5273
test_commit three &&
5374
test_push_failure upstream
5475
'
@@ -57,7 +78,6 @@ test_expect_success '"upstream" does not push on unconfigured branch' '
5778
git checkout master &&
5879
test_config branch.master.remote parent1 &&
5980
test_unconfig branch.master.merge &&
60-
test_config push.default upstream
6181
test_commit four &&
6282
test_push_failure upstream
6383
'
@@ -115,4 +135,41 @@ test_expect_success 'push to existing branch, upstream configured with different
115135
test_cmp expect-other-name actual-other-name
116136
'
117137

138+
# We are on 'master', which integrates with 'foo' from parent1
139+
# remote (set in test_pushdefault_workflow helper). Push to
140+
# parent1 in centralized, and push to parent2 in triangular workflow.
141+
# The parent1 repository has 'master' and 'foo' branches, while
142+
# the parent2 repository has only 'master' branch.
143+
#
144+
# test_pushdefault_workflow() arguments:
145+
# $1 = success or failure
146+
# $2 = push.default value
147+
# $3 = branch to check for actual output (master or foo)
148+
# $4 = [optional] switch to triangular workflow
149+
150+
# update parent1's master (which is not our upstream)
151+
test_pushdefault_workflow success current master
152+
153+
# update parent1's foo (which is our upstream)
154+
test_pushdefault_workflow success upstream foo
155+
156+
# upsream is foo which is not the name of the current branch
157+
test_pushdefault_workflow failure simple master
158+
159+
# master and foo are updated
160+
test_pushdefault_workflow success matching master
161+
162+
# master is updated
163+
test_pushdefault_workflow success current master triangular
164+
165+
# upstream mode cannot be used in triangular
166+
test_pushdefault_workflow failure upstream foo triangular
167+
168+
# in triangular, 'simple' works as 'current' and update the branch
169+
# with the same name.
170+
test_pushdefault_workflow success simple master triangular
171+
172+
# master is updated (parent2 does not have foo)
173+
test_pushdefault_workflow success matching master triangular
174+
118175
test_done

0 commit comments

Comments
 (0)