diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt index 8df10d0712..445341a906 100644 --- a/Documentation/config/branch.txt +++ b/Documentation/config/branch.txt @@ -40,8 +40,9 @@ branch..remote:: may be overridden with `remote.pushDefault` (for all branches). The remote to push to, for the current branch, may be further overridden by `branch..pushRemote`. If no remote is - configured, or if you are not on any branch, it defaults to - `origin` for fetching and `remote.pushDefault` for pushing. + configured, or if you are not on any branch and there is more than + one remote defined in the repository, it defaults to `origin` for + fetching and `remote.pushDefault` for pushing. Additionally, `.` (a period) is the current local repository (a dot-repository), see `branch..merge`'s final note below. diff --git a/remote.c b/remote.c index 42a4e7106e..930fdc9c2f 100644 --- a/remote.c +++ b/remote.c @@ -543,6 +543,8 @@ static const char *remotes_remote_for_branch(struct remote_state *remote_state, } if (explicit) *explicit = 0; + if (remote_state->remotes_nr == 1) + return remote_state->remotes[0]->name; return "origin"; } diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index f53f58895a..20d063fb9a 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -15,6 +15,10 @@ generate_references () { done } +test_expect_success 'dies when no remote found' ' + test_must_fail git ls-remote +' + test_expect_success setup ' >file && git add file && @@ -30,7 +34,8 @@ test_expect_success setup ' git show-ref -d >refs && sed -e "s/ / /" refs >>expected.all && - git remote add self "$(pwd)/.git" + git remote add self "$(pwd)/.git" && + git remote add self2 "." ' test_expect_success 'ls-remote --tags .git' ' @@ -83,11 +88,17 @@ test_expect_success 'ls-remote --sort="-refname" --tags self' ' test_cmp expect actual ' -test_expect_success 'dies when no remote specified and no default remotes found' ' +test_expect_success 'dies when no remote specified, multiple remotes found, and no default specified' ' test_must_fail git ls-remote ' -test_expect_success 'use "origin" when no remote specified' ' +test_expect_success 'succeeds when no remote specified but only one found' ' + test_when_finished git remote add self2 "." && + git remote remove self2 && + git ls-remote +' + +test_expect_success 'use "origin" when no remote specified and multiple found' ' URL="$(pwd)/.git" && echo "From $URL" >exp_err && diff --git a/t/t5528-push-default.sh b/t/t5528-push-default.sh index f280e00eb7..0d6c9869ed 100755 --- a/t/t5528-push-default.sh +++ b/t/t5528-push-default.sh @@ -94,13 +94,74 @@ test_expect_success '"upstream" does not push when remotes do not match' ' test_must_fail git push parent2 ' -test_expect_success 'push from/to new branch with upstream, matching and simple' ' +test_expect_success '"current" does not push when multiple remotes and none origin' ' + git checkout main && + test_config push.default current && + test_commit current-multi && + test_must_fail git push +' + +test_expect_success '"current" pushes when remote explicitly specified' ' + git checkout main && + test_config push.default current && + test_commit current-specified && + git push parent1 +' + +test_expect_success '"current" pushes to origin when no remote specified among multiple' ' + git checkout main && + test_config remote.origin.url repo1 && + test_config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" && + test_commit current-origin && + test_push_success current main +' + +test_expect_success '"current" pushes to single remote even when not specified' ' + git checkout main && + test_when_finished git remote add parent1 repo1 && + git remote remove parent1 && + test_commit current-implied && + test_push_success current main repo2 +' + +test_expect_success 'push from/to new branch with non-defaulted remote fails with upstream, matching, current and simple ' ' git checkout -b new-branch && test_push_failure simple && test_push_failure matching && + test_push_failure upstream && + test_push_failure current +' + +test_expect_success 'push from/to new branch fails with upstream and simple ' ' + git checkout -b new-branch-1 && + test_config branch.new-branch-1.remote parent1 && + test_push_failure simple && test_push_failure upstream ' +# The behavior here is surprising but not entirely wrong: +# - the current branch is used to determine the target remote +# - the "matching" push default pushes matching branches, *ignoring* the +# current new branch as it does not have upstream tracking +# - the default push succeeds +# +# A previous test expected this to fail, but for the wrong reasons: +# it expected a fail becaause the branch is new and cannot be pushed, but +# in fact it was failing because of an ambiguous remote +# +test_expect_failure 'push from/to new branch fails with matching ' ' + git checkout -b new-branch-2 && + test_config branch.new-branch-2.remote parent1 && + test_push_failure matching +' + +test_expect_success 'push from/to branch with tracking fails with nothing ' ' + git checkout -b tracked-branch && + test_config branch.tracked-branch.remote parent1 && + test_config branch.tracked-branch.merge refs/heads/tracked-branch && + test_push_failure nothing +' + test_expect_success '"matching" fails if none match' ' git init --bare empty && test_must_fail git push empty : 2>actual &&