In Git, what does push.default=simple do differently from current and upstream?
answer
- Only matters when you give no refspec
- Three live values differ on names versus upstream
- One of them refuses on a name mismatch
- One ignores the upstream entirely
- The old default pushed every matching branch
basics
~20 spush.default decides what a bare git push sends. simple, the default, pushes the current branch to a same-named remote branch and refuses when the upstream has a different name; upstream pushes to the upstream whatever it is called; current ignores names entirely.
solid answer
~50 sThese values only matter when `git push` is given no refspec. **`simple`** — the default in modern Git — pushes the current branch to a remote branch of the same name, and when you are pushing to the branch's upstream remote it additionally requires the upstream branch to *have* that same name, refusing otherwise. **`upstream`** pushes the current branch to its configured upstream branch even when the names differ, which is right for setups where local and remote naming intentionally diverge. **`current`** pushes to a same-named branch on the target remote and does not consult the upstream at all, so it works happily in triangular setups. Two legacy values remain: `matching`, the pre-2.0 default, pushed *every* local branch that had a same-named remote counterpart — the surprise `simple` was introduced to eliminate — and `nothing`, which requires an explicit refspec every time.
code
console · 9 lines$ git config push.default
simple
$ git branch -vv
* main 1a2b3c4 [origin/integration] Wire up parser
$ git push
fatal: The upstream branch of your current branch does not match
the name of your current branch.go deeper
Recall that a bare git push sends only the current branch under the modern default, and that a mismatched branch name is why Git sometimes asks you to spell out the destination.
Explain all three live values precisely: simple's same-name requirement against the upstream remote, upstream's name-agnostic behaviour, and current's indifference to upstream configuration.
Connect the values to workflows — triangular setups favour current, mismatched naming schemes favour upstream — and be able to explain why matching was retired as a safety fix.
Standardise the value deliberately per repository rather than relying on individuals' global settings, and pair it with push.autoSetupRemote so new contributors are not blocked by the no-upstream error.
## What the setting governs `push.default` is consulted only when you run `git push` (optionally with a remote) and give **no refspec**. Git must then invent one. The setting picks the rule it uses. If you always type `git push origin main:main`, the value is irrelevant to you. ## The values **`simple`** — the default in modern Git. Push the current branch to a remote branch of the same name. When the push target is the branch's **upstream remote**, additionally require that the upstream branch has the same name as the local branch; if it does not, refuse and tell you to name the destination explicitly. When pushing to some *other* remote, it behaves like `current`. The design goal is to be safe for both the centralised workflow (one remote, matching names) and the triangular one (fetch from one remote, push to another) without silently doing something surprising in either. **`upstream`** (historical alias `tracking`) — push the current branch to the branch it tracks, whatever that branch is called. This is the value you want when local and remote names legitimately differ, for example when everyone's local `main` tracks a differently named integration branch. It only works when the branch has an upstream, and only pushes to the upstream remote. **`current`** — push the current branch to a branch of the same name on whatever remote is being pushed to, creating it if necessary, without consulting the upstream at all. Convenient in triangular workflows where the push target is not the fetch source. **`matching`** — the default before Git 2.0. A bare `git push` pushed **every** local branch that had a same-named branch on the remote. Someone with ten stale local branches could publish all of them by typing four words, which is exactly why the default changed. **`nothing`** — refuse to push anything without an explicit refspec. Occasionally used to force deliberate pushes in sensitive repositories. ## The classic simple refusal Suppose local `main` tracks `origin/integration`. Under `upstream`, a bare `git push` sends `main` to `integration`. Under the default `simple`, Git refuses, because the names differ and it will not guess which you meant. The remedy is either an explicit `git push origin main:integration`, or setting `push.default = upstream` if this mismatch is your normal way of working. Candidates who have hit this remember it vividly; it is the main behavioural difference the question is asking about. ## The no-upstream case If the current branch has no upstream at all, a bare `git push` under `simple` fails with a message that the current branch has no upstream branch, suggesting `git push --set-upstream origin <name>`. Recent Git versions add a `push.autoSetupRemote` setting which makes that first bare push create the remote branch and set the upstream automatically, removing the most common friction point for new contributors without loosening what `push.default` guards. ## Where to set it `push.default` is ordinary configuration and follows the normal scope rules: system, global (`git config --global push.default simple`), and per-repository, with the most specific winning. Teams that rely on a non-default value should set it per repository or document it, since a global setting on one person's machine explains nothing about someone else's behaviour. ## What it does not change None of these values relax the fast-forward rule, alter what the receiving repository permits, or affect explicit refspecs. They choose a destination; the receiver still decides whether the update is allowed. Nor do they push tags: tags travel only with `--tags`, `--follow-tags`, or an explicit tag refspec. ## Answering well Say that the setting only applies to a bare push, describe `simple` including the same-name requirement against the upstream remote, contrast `upstream` (name-agnostic, upstream-only) and `current` (name-based, upstream-agnostic), and mention `matching` as the dangerous old default that motivated the change. That progression shows you understand the safety argument rather than having memorised a list.
- Your local main tracks origin/integration. What happens on a bare git push under the default?It refuses. Under `simple`, pushing to the branch's upstream remote requires the upstream branch to share the local branch's name, and `main` versus `integration` does not. Either name the destination explicitly with `git push origin main:integration`, or set `push.default = upstream` if mismatched names are your normal workflow.
- Why was matching replaced as the default?Because a bare `git push` under `matching` pushed every local branch that had a same-named branch on the remote, so unrelated half-finished branches were published by accident. `simple` narrows the action to the current branch and adds the name check, keeping the common case convenient while removing the surprise.
- What happens under simple when the branch has no upstream at all?The push fails with a message that the current branch has no upstream branch, suggesting `git push --set-upstream origin <name>`. Recent Git versions offer `push.autoSetupRemote`, which makes that first bare push create the remote branch and record the upstream in one step, without changing what push.default guards against.
saying these in an interview costs you the question
- Thinks push.default affects explicit refspec pushes
- Believes simple pushes all branches
- Says upstream and current are interchangeable
- Assumes the setting relaxes the fast-forward rule
- Thinks the value is configured on the server