Skip to content

Commit 8a649be

Browse files
TaoKgitster
authored andcommitted
push: default to single remote even when not named origin
With "push.default=current" configured, a simple "git push" will push to the same-name branch on the current branch's branch.<name>.pushRemote, or remote.pushDefault, or origin. If none of these are defined, the push will fail with error "fatal: No configured push destination". The same "default to origin if no config" behavior applies with "push.default=matching". Other commands use "origin" as a default when there are multiple options, but default to the single remote when there is only one - for example, "git checkout <something>". This "assume the single remote if there is only one" behavior is more friendly/useful than a defaulting behavior that only uses the name "origin" no matter what. Update "git push" to also default to the single remote (and finally fall back to "origin" as default if there are several), for "push.default=current" and for other current and future remote-defaulting push behaviors. This change also modifies the behavior of ls-remote in a consistent way, so defaulting not only supplies 'origin', but any single configured remote also. Document the change in behavior, correct incorrect assumptions in related tests, and add test cases reflecting this new single-remote-defaulting behavior. Signed-off-by: Tao Klerks <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bdaf1df commit 8a649be

File tree

4 files changed

+81
-6
lines changed

4 files changed

+81
-6
lines changed

Documentation/config/branch.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ branch.<name>.remote::
4040
may be overridden with `remote.pushDefault` (for all branches).
4141
The remote to push to, for the current branch, may be further
4242
overridden by `branch.<name>.pushRemote`. If no remote is
43-
configured, or if you are not on any branch, it defaults to
44-
`origin` for fetching and `remote.pushDefault` for pushing.
43+
configured, or if you are not on any branch and there is more than
44+
one remote defined in the repository, it defaults to `origin` for
45+
fetching and `remote.pushDefault` for pushing.
4546
Additionally, `.` (a period) is the current local repository
4647
(a dot-repository), see `branch.<name>.merge`'s final note below.
4748

remote.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,8 @@ static const char *remotes_remote_for_branch(struct remote_state *remote_state,
543543
}
544544
if (explicit)
545545
*explicit = 0;
546+
if (remote_state->remotes_nr == 1)
547+
return remote_state->remotes[0]->name;
546548
return "origin";
547549
}
548550

t/t5512-ls-remote.sh

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ generate_references () {
1515
done
1616
}
1717

18+
test_expect_success 'dies when no remote found' '
19+
test_must_fail git ls-remote
20+
'
21+
1822
test_expect_success setup '
1923
>file &&
2024
git add file &&
@@ -30,7 +34,8 @@ test_expect_success setup '
3034
git show-ref -d >refs &&
3135
sed -e "s/ / /" refs >>expected.all &&
3236
33-
git remote add self "$(pwd)/.git"
37+
git remote add self "$(pwd)/.git" &&
38+
git remote add self2 "."
3439
'
3540

3641
test_expect_success 'ls-remote --tags .git' '
@@ -83,11 +88,17 @@ test_expect_success 'ls-remote --sort="-refname" --tags self' '
8388
test_cmp expect actual
8489
'
8590

86-
test_expect_success 'dies when no remote specified and no default remotes found' '
91+
test_expect_success 'dies when no remote specified, multiple remotes found, and no default specified' '
8792
test_must_fail git ls-remote
8893
'
8994

90-
test_expect_success 'use "origin" when no remote specified' '
95+
test_expect_success 'succeeds when no remote specified but only one found' '
96+
test_when_finished git remote add self2 "." &&
97+
git remote remove self2 &&
98+
git ls-remote
99+
'
100+
101+
test_expect_success 'use "origin" when no remote specified and multiple found' '
91102
URL="$(pwd)/.git" &&
92103
echo "From $URL" >exp_err &&
93104

t/t5528-push-default.sh

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,74 @@ test_expect_success '"upstream" does not push when remotes do not match' '
9494
test_must_fail git push parent2
9595
'
9696

97-
test_expect_success 'push from/to new branch with upstream, matching and simple' '
97+
test_expect_success '"current" does not push when multiple remotes and none origin' '
98+
git checkout main &&
99+
test_config push.default current &&
100+
test_commit current-multi &&
101+
test_must_fail git push
102+
'
103+
104+
test_expect_success '"current" pushes when remote explicitly specified' '
105+
git checkout main &&
106+
test_config push.default current &&
107+
test_commit current-specified &&
108+
git push parent1
109+
'
110+
111+
test_expect_success '"current" pushes to origin when no remote specified among multiple' '
112+
git checkout main &&
113+
test_config remote.origin.url repo1 &&
114+
test_config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
115+
test_commit current-origin &&
116+
test_push_success current main
117+
'
118+
119+
test_expect_success '"current" pushes to single remote even when not specified' '
120+
git checkout main &&
121+
test_when_finished git remote add parent1 repo1 &&
122+
git remote remove parent1 &&
123+
test_commit current-implied &&
124+
test_push_success current main repo2
125+
'
126+
127+
test_expect_success 'push from/to new branch with non-defaulted remote fails with upstream, matching, current and simple ' '
98128
git checkout -b new-branch &&
99129
test_push_failure simple &&
100130
test_push_failure matching &&
131+
test_push_failure upstream &&
132+
test_push_failure current
133+
'
134+
135+
test_expect_success 'push from/to new branch fails with upstream and simple ' '
136+
git checkout -b new-branch-1 &&
137+
test_config branch.new-branch-1.remote parent1 &&
138+
test_push_failure simple &&
101139
test_push_failure upstream
102140
'
103141

142+
# The behavior here is surprising but not entirely wrong:
143+
# - the current branch is used to determine the target remote
144+
# - the "matching" push default pushes matching branches, *ignoring* the
145+
# current new branch as it does not have upstream tracking
146+
# - the default push succeeds
147+
#
148+
# A previous test expected this to fail, but for the wrong reasons:
149+
# it expected a fail becaause the branch is new and cannot be pushed, but
150+
# in fact it was failing because of an ambiguous remote
151+
#
152+
test_expect_failure 'push from/to new branch fails with matching ' '
153+
git checkout -b new-branch-2 &&
154+
test_config branch.new-branch-2.remote parent1 &&
155+
test_push_failure matching
156+
'
157+
158+
test_expect_success 'push from/to branch with tracking fails with nothing ' '
159+
git checkout -b tracked-branch &&
160+
test_config branch.tracked-branch.remote parent1 &&
161+
test_config branch.tracked-branch.merge refs/heads/tracked-branch &&
162+
test_push_failure nothing
163+
'
164+
104165
test_expect_success '"matching" fails if none match' '
105166
git init --bare empty &&
106167
test_must_fail git push empty : 2>actual &&

0 commit comments

Comments
 (0)