threads / patch / 64042

patch, 4 partsdoc: git-push: clarify DESCRIPTION section & refspec definition

Subject: [PATCH 0/4] doc: git-push: clarify DESCRIPTION section & refspec definition

## tl;dr

87 messages between Aug 26, 2025 and Oct 7, 2025. Diffs are folded; open one to read it.

replies: 86people: 5as markdown or json

Julia Evans via GitGitGadget· Aug 26, 2025, 20:40 UTC · lore

I surveyed 16 Git users about the git push man page. Here's a rewrite of the DESCRIPTION section and the definition of <refspec> based on the feedback. The goal is to clarify it while communicating the same information. The most common piece of feedback was that folks didn't understand what the term "ref" means. Most of the users who said they did not understand the term "ref" have been using Git for 10+ years.

The rewrite of the <refspec> section is more invasive than I usually prefer: I've tried to keep as much of the original text as possible, but if there are too many issues with it then I'll drop that patch from this series.

Julia Evans (4):
  doc: git-push: update intro
  doc: git-push: clarify "where to push"
  doc: git-push: clarify "what to push"
  doc: git-push: rewrite refspec specification
 Documentation/git-push.adoc | 204 ++++++++++++++++++------------------
 1 file changed, 103 insertions(+), 101 deletions(-)
base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1964%2Fjvns%2Fclarify-push-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1964/jvns/clarify-push-v1
Pull-Request: https://github.com/gitgitgadget/git/pull/1964
-- 
gitgitgadget
Julia Evans via GitGitGadget· Aug 26, 2025, 20:40 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH 1/4] doc: git-push: update intro

From: Julia Evans <julia@jvns.ca>
- Users don't understand what a "ref" is, expand it
- Remove "complete the given refs" (that phrase is confusing to many
  users, and it's obvious that pushing a branch involves sending the
  new code)
- Move down the reference to hooks, it's less important than the
  command's basic usage
Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)
Show changes to Documentation/git-push.adoc +5 −6
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index d1978650d60a..e73b64f61fd0 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -19,12 +19,8 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Updates remote refs using local refs, while sending objects
-necessary to complete the given refs.
-
-You can make interesting things happen to a repository
-every time you push into it, by setting up 'hooks' there.  See
-documentation for linkgit:git-receive-pack[1].
+Updates one or more branches, tags, or other references in a remote
+repository from your local repository.
 
 When the command line does not specify where to push with the
 `<repository>` argument, `branch.*.remote` configuration for the
@@ -44,6 +40,9 @@ corresponding upstream branch, but as a safety measure, the push is
 aborted if the upstream branch does not have the same name as the
 local one.
 
+You can make interesting things happen to a repository
+every time you push into it, by setting up 'hooks' there.  See
+documentation for linkgit:git-receive-pack[1].
 
 OPTIONS[[OPTIONS]]
 ------------------
-- 
gitgitgadget
D. Ben Knoble· Aug 28, 2025, 13:53 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH 1/4] doc: git-push: update intro

On Tue, Aug 26, 2025 at 4:40 PM Julia Evans via GitGitGadget <gitgitgadget@gmail.com> wrote:

>
> From: Julia Evans <julia@jvns.ca>
>
> - Users don't understand what a "ref" is, expand it
[snip]
Show 16 quoted lines
> diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
> index d1978650d60a..e73b64f61fd0 100644
> --- a/Documentation/git-push.adoc
> +++ b/Documentation/git-push.adoc
> @@ -19,12 +19,8 @@ SYNOPSIS
>  DESCRIPTION
>  -----------
>
> -Updates remote refs using local refs, while sending objects
> -necessary to complete the given refs.
> -
> -You can make interesting things happen to a repository
> -every time you push into it, by setting up 'hooks' there.  See
> -documentation for linkgit:git-receive-pack[1].
> +Updates one or more branches, tags, or other references in a remote
> +repository from your local repository.
Considering the glossary entry[1] is for "ref", not "reference", what about

(a) linking to the glossary (is this possible?), and/or (b) saying something like

    Updates one or more branches, tags, or other references (called "refs")…
?

[1]: "git help glossary", or https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-ref

Show 10 quoted lines
>
>  When the command line does not specify where to push with the
>  `<repository>` argument, `branch.*.remote` configuration for the
> @@ -44,6 +40,9 @@ corresponding upstream branch, but as a safety measure, the push is
>  aborted if the upstream branch does not have the same name as the
>  local one.
>
> +You can make interesting things happen to a repository
> +every time you push into it, by setting up 'hooks' there.  See
> +documentation for linkgit:git-receive-pack[1].
Seems reasonable to me. Thanks!
-- 
D. Ben Knoble
Junio C Hamano· Aug 28, 2025, 16:18 UTC · re: D. Ben Knoble · lore

Re: [PATCH 1/4] doc: git-push: update intro

"D. Ben Knoble" <ben.knoble@gmail.com> writes:
Show 14 quoted lines
>> +Updates one or more branches, tags, or other references in a remote
>> +repository from your local repository.
>
> Considering the glossary entry[1] is for "ref", not "reference", what about
>
> (a) linking to the glossary (is this possible?), and/or
> (b) saying something like
>
>     Updates one or more branches, tags, or other references (called "refs")…
>
> ?
>
> [1]: "git help glossary", or
> https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-ref

Both sound good ideas. We should make sure that readers are aware of the glossary by linking into it from more places.

Kristoffer Haugsbakk· Aug 29, 2025, 07:20 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/4] doc: git-push: update intro

On Thu, Aug 28, 2025, at 18:18, Junio C Hamano wrote:
Show 19 quoted lines
> "D. Ben Knoble" <ben.knoble@gmail.com> writes:
>
>>> +Updates one or more branches, tags, or other references in a remote
>>> +repository from your local repository.
>>
>> Considering the glossary entry[1] is for "ref", not "reference", what about
>>
>> (a) linking to the glossary (is this possible?), and/or
>> (b) saying something like
>>
>>     Updates one or more branches, tags, or other references (called "refs")…
>>
>> ?
>>
>> [1]: "git help glossary", or
>> https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-ref
>
> Both sound good ideas.  We should make sure that readers are aware
> of the glossary by linking into it from more places.

I wonder if the essential commands that everyone is likely to use ought to have footnotes which point to the glossary for all the jargon. That way people can skim past them if they don’t care, especially if there is (say) at most one footnote after every sentence.

I imagine you could get a lot of parentheticals without this approach.
-- 
Kristoffer Haugsbakk
Julia Evans· Aug 28, 2025, 17:47 UTC · re: D. Ben Knoble · lore

Re: [PATCH 1/4] doc: git-push: update intro

> Considering the glossary entry[1] is for "ref", not "reference", what about
>
> (a) linking to the glossary (is this possible?), and/or

I like this idea. Over on the HTML docs side (https://github.com/git/git-scm.com/pull/2040) I've been working on a way to show an interactive tooltip from the glossary when people hover over "jargon" terms. The goal there is to make the glossary a lot more discoverable.

Right now it only works for terms inside angle brackets (like `<ref>`), but I've been thinking of adding a `linkgitglossary:` AsciiDoc macro or something (similar to `linkgit:`) to link terms to specific glossary entries. It's hard to tell what that should do in the terminal version of the man pages (maybe nothing!), but it could make the HTML versions a lot easier to use.

D. Ben Knoble· Aug 28, 2025, 19:39 UTC · re: Julia Evans · lore

Re: [PATCH 1/4] doc: git-push: update intro

+cc Junio due to his reply to my reply
On Thu, Aug 28, 2025 at 1:48 PM Julia Evans <julia@jvns.ca> wrote:
Show 16 quoted lines
>
> > Considering the glossary entry[1] is for "ref", not "reference", what about
> >
> > (a) linking to the glossary (is this possible?), and/or
>
> I like this idea. Over on the HTML docs side
> (https://github.com/git/git-scm.com/pull/2040)
> I've been working on a way to show an interactive tooltip from the glossary when
> people hover over "jargon" terms. The goal there is to make the glossary a lot
> more discoverable.
>
> Right now it only works for terms inside angle brackets (like `<ref>`), but
> I've been thinking of adding a `linkgitglossary:` AsciiDoc macro or something
> (similar to `linkgit:`) to link terms to specific glossary entries. It's hard
> to tell what that should do in the terminal version of the man pages
> (maybe nothing!), but it could make the HTML versions a lot easier to use.

I think we could so similar to existing "linkgit:" and expand to "gitglossary(7)" (or "git help glossary")

-- 
D. Ben Knoble
Julia Evans via GitGitGadget· Aug 26, 2025, 20:40 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH 2/4] doc: git-push: clarify "where to push"

From: Julia Evans <julia@jvns.ca>
Signed-off-by: Julia Evans <julia@jvns.ca>

Be clearer about what we're describing ("which repository" instead of "what to push"), and start with a positive "try X, then Y, then Z" instead of a negative ("if X is not specified..").

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
Show changes to Documentation/git-push.adoc +4 −4
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index e73b64f61fd0..5c934486c33d 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -22,10 +22,10 @@ DESCRIPTION
 Updates one or more branches, tags, or other references in a remote
 repository from your local repository.
 
-When the command line does not specify where to push with the
-`<repository>` argument, `branch.*.remote` configuration for the
-current branch is consulted to determine where to push.  If the
-configuration is missing, it defaults to 'origin'.
+To decide which repository to push to, Git uses the `<repository>`
+argument (for example `git push dev`), then if that's not specified the
+`branch.*.remote` configuration for the current branch, and then defaults
+to `origin`.
 
 When the command line does not specify what to push with `<refspec>...`
 arguments or `--all`, `--mirror`, `--tags` options, the command finds
-- 
gitgitgadget
Junio C Hamano· Aug 27, 2025, 00:05 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH 2/4] doc: git-push: clarify "where to push"

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 7 quoted lines
> From: Julia Evans <julia@jvns.ca>
>
> Signed-off-by: Julia Evans <julia@jvns.ca>
>
> Be clearer about what we're describing ("which repository" instead of
> "what to push"), and start with a positive "try X, then Y, then Z"
> instead of a negative ("if X is not specified..").

Since I like this simple rule so much, if it is generally applicable everywhere, I'd like to have it or a variant of it in one of our developer facing documentation as a tip to write better documentation.

> Signed-off-by: Julia Evans <julia@jvns.ca>

There is some funny ordering problem with the commit log body and sign-off.

Show 20 quoted lines
> ---
>  Documentation/git-push.adoc | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
> index e73b64f61fd0..5c934486c33d 100644
> --- a/Documentation/git-push.adoc
> +++ b/Documentation/git-push.adoc
> @@ -22,10 +22,10 @@ DESCRIPTION
>  Updates one or more branches, tags, or other references in a remote
>  repository from your local repository.
>  
> -When the command line does not specify where to push with the
> -`<repository>` argument, `branch.*.remote` configuration for the
> -current branch is consulted to determine where to push.  If the
> -configuration is missing, it defaults to 'origin'.
> +To decide which repository to push to, Git uses the `<repository>`
> +argument (for example `git push dev`), then if that's not specified the
> +`branch.*.remote` configuration for the current branch, and then defaults
> +to `origin`.
Very nicely done.
>  When the command line does not specify what to push with `<refspec>...`
>  arguments or `--all`, `--mirror`, `--tags` options, the command finds
Julia Evans via GitGitGadget· Aug 26, 2025, 20:40 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH 3/4] doc: git-push: clarify "what to push"

From: Julia Evans <julia@jvns.ca>
- Be more explicit about what we're describing ("which branches" instead
  of "what to push")
- Split out the ways to specify which branches into a numbered list,
  since there are 5 different ways to specify it and it's a lot to parse
  in paragraph form
- The explanation of "push.default=simple" is confusing to some users,
  use an explanation more similar to the one in `man git-config`
- Mention the most common case where push.default=simple is likely to
  fail, and how to handle it
Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)
Show changes to Documentation/git-push.adoc +13 −10
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index 5c934486c33d..0232195515c9 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -27,18 +27,21 @@ argument (for example `git push dev`), then if that's not specified the
 `branch.*.remote` configuration for the current branch, and then defaults
 to `origin`.
 
-When the command line does not specify what to push with `<refspec>...`
-arguments or `--all`, `--mirror`, `--tags` options, the command finds
-the default `<refspec>` by consulting `remote.*.push` configuration,
-and if it is not found, honors `push.default` configuration to decide
-what to push (See linkgit:git-config[1] for the meaning of `push.default`).
+To decide which branches, tags, or other refs to push, Git uses
+(in order of precedence):
+
+1. The <refspec> argument(s) (for example `main` in `git push origin main`)
+   or the `--all`, `--mirror`, or `--tags` options
+2. The `remote.*.push` configuration for the current branch
+3. The `push.default` configuration (See linkgit:git-config[1] for
+   the meaning of `push.default`).
 
 When neither the command-line nor the configuration specifies what to
-push, the default behavior is used, which corresponds to the `simple`
-value for `push.default`: the current branch is pushed to the
-corresponding upstream branch, but as a safety measure, the push is
-aborted if the upstream branch does not have the same name as the
-local one.
+push, the current branch is pushed to the branch with the same name
+on the remote. The current branch must have a configured upstream with
+the same name, so this will fail when pushing a new branch.
+You can run `git push -u <repository> <current-branch>`
+to configure the upstream.
 
 You can make interesting things happen to a repository
 every time you push into it, by setting up 'hooks' there.  See
-- 
gitgitgadget
Junio C Hamano· Aug 26, 2025, 23:57 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH 3/4] doc: git-push: clarify "what to push"

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 13 quoted lines
> -When the command line does not specify what to push with `<refspec>...`
> -arguments or `--all`, `--mirror`, `--tags` options, the command finds
> -the default `<refspec>` by consulting `remote.*.push` configuration,
> -and if it is not found, honors `push.default` configuration to decide
> -what to push (See linkgit:git-config[1] for the meaning of `push.default`).
> +To decide which branches, tags, or other refs to push, Git uses
> +(in order of precedence):
> +
> +1. The <refspec> argument(s) (for example `main` in `git push origin main`)
> +   or the `--all`, `--mirror`, or `--tags` options
> +2. The `remote.*.push` configuration for the current branch
> +3. The `push.default` configuration (See linkgit:git-config[1] for
> +   the meaning of `push.default`).

The use of numbered list does make very good sense here, as we (at least conceptually) examine these rules in the order.

Show 9 quoted lines
>  When neither the command-line nor the configuration specifies what to
> -push, the default behavior is used, which corresponds to the `simple`
> -value for `push.default`: the current branch is pushed to the
> -corresponding upstream branch, but as a safety measure, the push is
> -aborted if the upstream branch does not have the same name as the
> -local one.
> +push, the current branch is pushed to the branch with the same name
> +on the remote. The current branch must have a configured upstream with
> +the same name, so this will fail when pushing a new branch.
Is the last sentence correct?
    $ cd /var/tmp/playpen
    $ git clone https://github.com/git/git src
    $ git clone --no-local --bare src dst
    $ cd src
    $ git checkout -b alter
    $ git commit -m 'empty' --allow-empty
    $ git -c push.default=simple push ../dst
    Enumerating objects: 1, done.
    Counting objects: 100% (1/1), done.
    Writing objects: 100% (1/1), 185 bytes | 92.00 KiB/s, done.
    Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
    To ../dst
     * [new branch]            alter -> alter

In "src" repository that is a fresh clone without any customization, the current branch "alter" does not have any configured upstream.

Puzzled....
Julia Evans· Aug 27, 2025, 13:52 UTC · re: Junio C Hamano · lore

Re: [PATCH 3/4] doc: git-push: clarify "what to push"

Show 20 quoted lines
> Is the last sentence correct?
>
>     $ cd /var/tmp/playpen
>     $ git clone https://github.com/git/git src
>     $ git clone --no-local --bare src dst
>     $ cd src
>     $ git checkout -b alter
>     $ git commit -m 'empty' --allow-empty
>     $ git -c push.default=simple push ../dst
>     Enumerating objects: 1, done.
>     Counting objects: 100% (1/1), done.
>     Writing objects: 100% (1/1), 185 bytes | 92.00 KiB/s, done.
>     Total 1 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
>     To ../dst
>      * [new branch]            alter -> alter
>
> In "src" repository that is a fresh clone without any customization,
> the current branch "alter" does not have any configured upstream.
>
> Puzzled....

It looks like Git behaves differently depending on whether the remote being pushed to is named "origin" or not: in this example the push fails to "origin" but succeeds to a differently named remote.

$ git clone https://github.com/jvns/vue3-tiny-template src
$ cd src
$ git remote add origin2 https://github.com/jvns/vue3-tiny-template
$ git checkout -b alter
$ git -c push.default=simple push origin --dry-run
fatal: The current branch alter has no upstream branch.
$ git -c push.default=simple push origin2 --dry-run
To github.com:jvns/vue3-tiny-template
 * [new branch]      alter -> alter

I tried to find the responsible code by adding some debug print statements (in this commit: https://github.com/git/git/commit/541e5d7cf61f970a5653ab496e5c3111271654a1)

It looks like push.simple has some kind of "same remote" checking, and if the branch has no tracking information, then origin is considered to be the "same remote" (so pushing is not allowed), but origin2 is not the "same remote", so it is allowed

D. Ben Knoble· Aug 28, 2025, 14:25 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH 3/4] doc: git-push: clarify "what to push"

On Tue, Aug 26, 2025 at 4:40 PM Julia Evans via GitGitGadget <gitgitgadget@gmail.com> wrote:

Show 5 quoted lines
>
> From: Julia Evans <julia@jvns.ca>
>
> - Be more explicit about what we're describing ("which branches" instead
>   of "what to push")

Reading this, I thought we would lose precision ("refspec" -> "branches"), but: the patch (correctly) includes more than branches. Perhaps

    - Be more explicit about what we're describing ("which branches,
[etc.]" instead of "what to push")
?
Show 46 quoted lines
> - Split out the ways to specify which branches into a numbered list,
>   since there are 5 different ways to specify it and it's a lot to parse
>   in paragraph form
> - The explanation of "push.default=simple" is confusing to some users,
>   use an explanation more similar to the one in `man git-config`
> - Mention the most common case where push.default=simple is likely to
>   fail, and how to handle it
>
> Signed-off-by: Julia Evans <julia@jvns.ca>
> ---
>  Documentation/git-push.adoc | 23 +++++++++++++----------
>  1 file changed, 13 insertions(+), 10 deletions(-)
>
> diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
> index 5c934486c33d..0232195515c9 100644
> --- a/Documentation/git-push.adoc
> +++ b/Documentation/git-push.adoc
> @@ -27,18 +27,21 @@ argument (for example `git push dev`), then if that's not specified the
>  `branch.*.remote` configuration for the current branch, and then defaults
>  to `origin`.
>
> -When the command line does not specify what to push with `<refspec>...`
> -arguments or `--all`, `--mirror`, `--tags` options, the command finds
> -the default `<refspec>` by consulting `remote.*.push` configuration,
> -and if it is not found, honors `push.default` configuration to decide
> -what to push (See linkgit:git-config[1] for the meaning of `push.default`).
> +To decide which branches, tags, or other refs to push, Git uses
> +(in order of precedence):
> +
> +1. The <refspec> argument(s) (for example `main` in `git push origin main`)
> +   or the `--all`, `--mirror`, or `--tags` options
> +2. The `remote.*.push` configuration for the current branch
> +3. The `push.default` configuration (See linkgit:git-config[1] for
> +   the meaning of `push.default`).
>
>  When neither the command-line nor the configuration specifies what to
> -push, the default behavior is used, which corresponds to the `simple`
> -value for `push.default`: the current branch is pushed to the
> -corresponding upstream branch, but as a safety measure, the push is
> -aborted if the upstream branch does not have the same name as the
> -local one.
> +push, the current branch is pushed to the branch with the same name
> +on the remote. The current branch must have a configured upstream with
> +the same name, so this will fail when pushing a new branch.
> +You can run `git push -u <repository> <current-branch>`
> +to configure the upstream.

I think we've lost the mention of `push.default` here, which we'd probably like to keep?

Also, I (personally) dislike teach "git push -u <repo> <branch>"
because it leads to some confusion. Let me try to explain myself:
- The way Git treats the configured upstream is the place to pull
from, merge from, rebase onto, etc., configured by branch.X.merge and
branch.X.remote. There is a (possibly!) separate "push to" place
configured (somewhat confusingly) with push.default and
remote.pushDefault.
- The way GitHub and others encourage setting upstream to the place
you push means you have to work a bit harder to pull, merge, rebase
from the semantic upstream (the thing you forked from, not the place
you push to): "git pull <remote> <branch>", "git rebase origin/main",
etc.
- There is, of course, another way that upstream is used: for
"ahead-behind" information in Git's status output. It is convenient to
know where you stand, and Git unfortunately does not provide an easy
way to see the same information against @{push} instead of
@{upstream}. I use some version of "git show-branch HEAD HEAD@{push}"
and a custom "git-div" script [1] for this…

Anyway, point is, I think defaulting to @{upstream} as the place you push has a nice benefit ("git status" shows me when I haven't pushed recently), but also is specific to a workflow where you push and pull from the same places. I find that _most_ of the time I'm actually doing something triangular (even when I push to and pull from the same repository, I rarely push to and pull from the same _branch_), and configuring things a different way affords me many other conveniences. For example, "git push" and "git pull" without extra flags are arguments just DWIM.

The confusion I alluded to earlier is that folks rarely learn this is an option and (in my estimation) lose out on an essential aspect of what makes Git distributed as opposed to centralized. It also leads to some confusion over what the term upstream means. And the extra "push.default explanation is sometimes inaccurate" doesn't help :)

I don't think this is a blocker for this patch, but I do have a bit of a knee-jerk reaction to this particular piece of (common-on-the-internet) advice :) Hope that makes sense.

[1]: https://github.com/benknoble/Dotfiles/blob/master/links/bin/git-div

PS I seek a better way to explain this whole idea, so my apologies for the confused rant.

-- 
D. Ben Knoble
Julia Evans via GitGitGadget· Aug 26, 2025, 20:40 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH 4/4] doc: git-push: rewrite refspec specification

From: Julia Evans <julia@jvns.ca>
- Originally it said that a refspec was `+<src>:<dst>`, but then later
  contradicted itself by saying that the `:<dst>` is optional.
  Mention that `:<dst>` is optional much earlier.
- Put the complex sets of rules about different refspec forms
  in lists instead of in long paragraphs of prose
- Add examples for the various types of refspecs
  (negative, deletion, pattern, etc)
- Previously `*` and `^` were not mentioned, mention them
- Explain what `+` does earlier
- Remove "might be added in the future" (it's a given that software
  might change in the future)
Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 164 ++++++++++++++++++------------------
 1 file changed, 82 insertions(+), 82 deletions(-)
Show changes to Documentation/git-push.adoc +82 −80
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index 0232195515c9..78d433c60c51 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -57,77 +57,74 @@ OPTIONS[[OPTIONS]]
 
 <refspec>...::
 	Specify what destination ref to update with what source object.
-	The format of a <refspec> parameter is an optional plus
-	`+`, followed by the source object <src>, followed
-	by a colon `:`, followed by the destination ref <dst>.
-+
-The <src> is often the name of the branch you would want to push, but
-it can be any arbitrary "SHA-1 expression", such as `master~4` or
-`HEAD` (see linkgit:gitrevisions[7]).
-+
-The <dst> tells which ref on the remote side is updated with this
-push. Arbitrary expressions cannot be used here, an actual ref must
-be named.
-If `git push [<repository>]` without any `<refspec>` argument is set to
-update some ref at the destination with `<src>` with
-`remote.<repository>.push` configuration variable, `:<dst>` part can
-be omitted--such a push will update a ref that `<src>` normally updates
-without any `<refspec>` on the command line.  Otherwise, missing
-`:<dst>` means to update the same ref as the `<src>`.
-+
-If <dst> doesn't start with `refs/` (e.g. `refs/heads/master`) we will
-try to infer where in `refs/*` on the destination <repository> it
-belongs based on the type of <src> being pushed and whether <dst>
-is ambiguous.
 +
---
-* If <dst> unambiguously refers to a ref on the <repository> remote,
-  then push to that ref.
-
-* If <src> resolves to a ref starting with refs/heads/ or refs/tags/,
-  then prepend that to <dst>.
-
-* Other ambiguity resolutions might be added in the future, but for
-  now any other cases will error out with an error indicating what we
-  tried, and depending on the `advice.pushUnqualifiedRefname`
-  configuration (see linkgit:git-config[1]) suggest what refs/
-  namespace you may have wanted to push to.
-
---
-+
-The object referenced by <src> is used to update the <dst> reference
-on the remote side. Whether this is allowed depends on where in
-`refs/*` the <dst> reference lives as described in detail below, in
-those sections "update" means any modifications except deletes, which
-as noted after the next few sections are treated differently.
-+
-The `refs/heads/*` namespace will only accept commit objects, and
-updates only if they can be fast-forwarded.
-+
-The `refs/tags/*` namespace will accept any kind of object (as
-commits, trees and blobs can be tagged), and any updates to them will
-be rejected.
-+
-It's possible to push any type of object to any namespace outside of
-`refs/{tags,heads}/*`. In the case of tags and commits, these will be
-treated as if they were the commits inside `refs/heads/*` for the
-purposes of whether the update is allowed.
-+
-I.e. a fast-forward of commits and tags outside `refs/{tags,heads}/*`
-is allowed, even in cases where what's being fast-forwarded is not a
-commit, but a tag object which happens to point to a new commit which
-is a fast-forward of the commit the last tag (or commit) it's
-replacing. Replacing a tag with an entirely different tag is also
-allowed, if it points to the same commit, as well as pushing a peeled
-tag, i.e. pushing the commit that existing tag object points to, or a
-new tag object which an existing commit points to.
-+
-Tree and blob objects outside of `refs/{tags,heads}/*` will be treated
-the same way as if they were inside `refs/tags/*`, any update of them
-will be rejected.
-+
-All of the rules described above about what's not allowed as an update
-can be overridden by adding an the optional leading `+` to a refspec
+The format for a refspec is [+]<src>[:<dst>], for example `main`,
+`main:other`, or `HEAD^:refs/heads/main`.
++
+The `<src>` is often the name of the local branch to push, but it can be
+any arbitrary "SHA-1 expression" (see linkgit:gitrevisions[7]).
++
+The `<dst>` determines what to update on the remote side. It must be the
+name of a branch, tag, or other ref, not an arbitrary expression.
+`:<dst>` is optional.
++
+`+` is optional and does the same thing as `--force`.
++
+You can write a refspec using the fully expanded form (for
+example `main:refs/heads/main`) which specifies the exact source
+and destination, or with a shorter form (for example `main` or
+`main:other`). Here are the rules for how refspecs are expanded,
+as well as various other special refspec forms:
++
+ 1. `<src>` without a `:<dst>` means to update the same ref as the
+	`<src>`, unless the `remote.<repository>.push` configuration specifies a
+	different <dst>. For example, if `main` is a branch, then the refspec
+    `main` expands to `main:refs/heads/main`.
+ 2. If <dst> unambiguously refers to a ref on the <repository> remote,
+    then expand it to that ref. For example, if `v1.0` is a tag on the
+    remote, then `HEAD:v1.0` expands to `HEAD:refs/tags/v1.0`.
+ 3. If <src> resolves to a ref starting with refs/heads/ or refs/tags/,
+    then prepend that to <dst>. For example, if `main` is a branch, then
+    `main:other` expands to `main:refs/heads/other`
+ 4. The special refspec `:` (or `+:` to allow non-fast-forward updates)
+    directs Git to push "matching" branches: for every branch that exists on
+    the local side, the remote side is updated if a branch of the same name
+    already exists on the remote side.
+ 5. `tag <tag>` expands to `refs/tags/<tag>:refs/tags/<tag>`.
+ 6. <src> may contain a * to indicate a simple pattern match.
+    This works like a glob that matches any ref matching the pattern.
+    There must be only one * in both the <src> and <dst>.
+    It will map refs to the destination by replacing the * with the
+    contents matched from the source. For example, `refs/heads/*:refs/heads/*`
+    will push all branches.
+ 7. A refspec starting with ^ is a negative refspec.
+    This specifies refs to exclude. A ref will be considered to
+    match if it matches at least one positive refspec, and does not
+    match any negative refspec. Negative refspecs can be pattern refspecs.
+    They must only contain a <src>.
+    Fully spelled out hex object names are also not supported.
+    For example, `git push origin 'refs/heads/*' '^refs/heads/dev-*'`
+    will push all branches except for those starting with `dev-`
+ 8. If `<src>` is empty, it deletes the <dst> ref from the remote
+    repository. For example, `git push origin :dev` will
+    delete the `dev` branch.
+    Deletions are always accepted without a leading `+` in the
+    refspec (or `--force`), except when forbidden by configuration or hooks.
+    See `receive.denyDeletes` in linkgit:git-config[1] and `pre-receive` and
+    `update` in linkgit:githooks[5].
+ 9. If the refspec can't be expanded unambiguously, error
+    out with an error indicating what was
+    tried, and depending on the `advice.pushUnqualifiedRefname`
+    configuration (see linkgit:git-config[1]) suggest what refs/
+    namespace you may have wanted to push to.
+
++
+Not all updates are allowed: it depends on what kind of destination
+you're pushing to. In the following rules "update" means any
+modifications except deletes, which as noted above are treated differently.
++
+All of these rules
+can be overridden by adding the optional leading `+` to a refspec
 (or using `--force` command line option). The only exception to this
 is that no amount of forcing will make the `refs/heads/*` namespace
 accept a non-commit object. Hooks and configuration can also override
@@ -135,18 +132,21 @@ or amend these rules, see e.g. `receive.denyNonFastForwards` in
 linkgit:git-config[1] and `pre-receive` and `update` in
 linkgit:githooks[5].
 +
-Pushing an empty <src> allows you to delete the <dst> ref from the
-remote repository. Deletions are always accepted without a leading `+`
-in the refspec (or `--force`), except when forbidden by configuration
-or hooks. See `receive.denyDeletes` in linkgit:git-config[1] and
-`pre-receive` and `update` in linkgit:githooks[5].
-+
-The special refspec `:` (or `+:` to allow non-fast-forward updates)
-directs Git to push "matching" branches: for every branch that exists on
-the local side, the remote side is updated if a branch of the same name
-already exists on the remote side.
-+
-`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
+1. If the destination is a **branch** (`refs/heads/*`): the source must
+   be a commit object, and only fast-forward updates are allowed.
+2. If the destination is a **tag** (`refs/tags/*`):  the source can
+   be any object (as commits, trees and blobs can be tagged), and any
+   updates to them will be rejected.
+3. For destinations outside of `refs/{tags,heads}/*`:
+   * If the source is a tree or blob object, any updates will be rejected
+   * If the source is a tag or commit object, any fast-forward update
+     is allowed, even in cases where what's being fast-forwarded is not a
+     commit, but a tag object which happens to point to a new commit which
+     is a fast-forward of the commit the last tag (or commit) it's
+     replacing. Replacing a tag with an entirely different tag is also
+     allowed, if it points to the same commit, as well as pushing a peeled
+     tag, i.e. pushing the commit that existing tag object points to, or a
+     new tag object which an existing commit points to.
 
 --all::
 --branches::
-- 
gitgitgadget
Junio C Hamano· Aug 26, 2025, 23:34 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH 4/4] doc: git-push: rewrite refspec specification

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 98 quoted lines
> From: Julia Evans <julia@jvns.ca>
>
> - Originally it said that a refspec was `+<src>:<dst>`, but then later
>   contradicted itself by saying that the `:<dst>` is optional.
>   Mention that `:<dst>` is optional much earlier.
> - Put the complex sets of rules about different refspec forms
>   in lists instead of in long paragraphs of prose
> - Add examples for the various types of refspecs
>   (negative, deletion, pattern, etc)
> - Previously `*` and `^` were not mentioned, mention them
> - Explain what `+` does earlier
> - Remove "might be added in the future" (it's a given that software
>   might change in the future)
>
> Signed-off-by: Julia Evans <julia@jvns.ca>
> ---
>  Documentation/git-push.adoc | 164 ++++++++++++++++++------------------
>  1 file changed, 82 insertions(+), 82 deletions(-)
>
> diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
> index 0232195515c9..78d433c60c51 100644
> --- a/Documentation/git-push.adoc
> +++ b/Documentation/git-push.adoc
> @@ -57,77 +57,74 @@ OPTIONS[[OPTIONS]]
>  
>  <refspec>...::
>  	Specify what destination ref to update with what source object.
> -	The format of a <refspec> parameter is an optional plus
> -	`+`, followed by the source object <src>, followed
> -	by a colon `:`, followed by the destination ref <dst>.
> -+
> -The <src> is often the name of the branch you would want to push, but
> -it can be any arbitrary "SHA-1 expression", such as `master~4` or
> -`HEAD` (see linkgit:gitrevisions[7]).
> -+
> -The <dst> tells which ref on the remote side is updated with this
> -push. Arbitrary expressions cannot be used here, an actual ref must
> -be named.
> -If `git push [<repository>]` without any `<refspec>` argument is set to
> -update some ref at the destination with `<src>` with
> -`remote.<repository>.push` configuration variable, `:<dst>` part can
> -be omitted--such a push will update a ref that `<src>` normally updates
> -without any `<refspec>` on the command line.  Otherwise, missing
> -`:<dst>` means to update the same ref as the `<src>`.
> -+
> -If <dst> doesn't start with `refs/` (e.g. `refs/heads/master`) we will
> -try to infer where in `refs/*` on the destination <repository> it
> -belongs based on the type of <src> being pushed and whether <dst>
> -is ambiguous.
>  +
> ---
> -* If <dst> unambiguously refers to a ref on the <repository> remote,
> -  then push to that ref.
> -
> -* If <src> resolves to a ref starting with refs/heads/ or refs/tags/,
> -  then prepend that to <dst>.
> -
> -* Other ambiguity resolutions might be added in the future, but for
> -  now any other cases will error out with an error indicating what we
> -  tried, and depending on the `advice.pushUnqualifiedRefname`
> -  configuration (see linkgit:git-config[1]) suggest what refs/
> -  namespace you may have wanted to push to.
> -
> ---
> -+
> -The object referenced by <src> is used to update the <dst> reference
> -on the remote side. Whether this is allowed depends on where in
> -`refs/*` the <dst> reference lives as described in detail below, in
> -those sections "update" means any modifications except deletes, which
> -as noted after the next few sections are treated differently.
> -+
> -The `refs/heads/*` namespace will only accept commit objects, and
> -updates only if they can be fast-forwarded.
> -+
> -The `refs/tags/*` namespace will accept any kind of object (as
> -commits, trees and blobs can be tagged), and any updates to them will
> -be rejected.
> -+
> -It's possible to push any type of object to any namespace outside of
> -`refs/{tags,heads}/*`. In the case of tags and commits, these will be
> -treated as if they were the commits inside `refs/heads/*` for the
> -purposes of whether the update is allowed.
> -+
> -I.e. a fast-forward of commits and tags outside `refs/{tags,heads}/*`
> -is allowed, even in cases where what's being fast-forwarded is not a
> -commit, but a tag object which happens to point to a new commit which
> -is a fast-forward of the commit the last tag (or commit) it's
> -replacing. Replacing a tag with an entirely different tag is also
> -allowed, if it points to the same commit, as well as pushing a peeled
> -tag, i.e. pushing the commit that existing tag object points to, or a
> -new tag object which an existing commit points to.
> -+
> -Tree and blob objects outside of `refs/{tags,heads}/*` will be treated
> -the same way as if they were inside `refs/tags/*`, any update of them
> -will be rejected.
> -+
> -All of the rules described above about what's not allowed as an update
> -can be overridden by adding an the optional leading `+` to a refspec

All of the above is fairly accurate, even though they are densely written and at places somewhat redundant.

Show 8 quoted lines
> +The format for a refspec is [+]<src>[:<dst>], for example `main`,
> +`main:other`, or `HEAD^:refs/heads/main`.
> ++
> +The `<src>` is often the name of the local branch to push, but it can be
> +any arbitrary "SHA-1 expression" (see linkgit:gitrevisions[7]).
> ++
> +The `<dst>` determines what to update on the remote side. It must be the
> +name of a branch, tag, or other ref, not an arbitrary expression.
Concise and simpler beginning is good.
> +`:<dst>` is optional.

It may be technically true, but I am not sure if it is a good idea to say it here. Without "when missing, <dst> is inferred with these rules", saying just "is optional" naturally invites a puzzlement: when do we need to supply it and for what?

As you are going to say what happens when you omit it very soon, and you already have said with [:<dst>] that it is optional, perhaps you can scratch this sentence.

> +`+` is optional and does the same thing as `--force`.

Ditto; this one is less bad than the :<dst> thing, because at least it tells us what it means. But we are going to talk about when an update is not allowed (we haven't even hinted that some updates may not be allowed yet) much later, "the same as `--force`" is probably a bit premature at this point in the documentation.

> +You can write a refspec using the fully expanded form (for
> +example `main:refs/heads/main`) which specifies the exact source

This example is not fully expanded. refs/heads/main:refs/heads/main would be, though.

> +and destination, or with a shorter form (for example `main` or
> +`main:other`). Here are the rules for how refspecs are expanded,
> +as well as various other special refspec forms:
> ++

I am not sure it is easier to read with numbered list. It is not like these rules are applied in this order, or anything like that, right?

Show 14 quoted lines
> + 1. `<src>` without a `:<dst>` means to update the same ref as the
> +	`<src>`, unless the `remote.<repository>.push` configuration specifies a
> +	different <dst>. For example, if `main` is a branch, then the refspec
> +    `main` expands to `main:refs/heads/main`.
> + 2. If <dst> unambiguously refers to a ref on the <repository> remote,
> +    then expand it to that ref. For example, if `v1.0` is a tag on the
> +    remote, then `HEAD:v1.0` expands to `HEAD:refs/tags/v1.0`.
> + 3. If <src> resolves to a ref starting with refs/heads/ or refs/tags/,
> +    then prepend that to <dst>. For example, if `main` is a branch, then
> +    `main:other` expands to `main:refs/heads/other`
> + 4. The special refspec `:` (or `+:` to allow non-fast-forward updates)
> +    directs Git to push "matching" branches: for every branch that exists on
> +    the local side, the remote side is updated if a branch of the same name
> +    already exists on the remote side.

Good to see that the oddballs like this and an empty one, originally described elsewhere, collected in the same list. An entry like this that describes a special notation, not a concrete single refspec, however is a bit hard to read when mixed with other more normal rules. Perhaps move it down together with the "push void to remove" at the top of the list?

> + 5. `tag <tag>` expands to `refs/tags/<tag>:refs/tags/<tag>`.

A tangent. Is this a refspec you can write in .git/config, e.g.

	[remote "origin"]
		push = tag v1.0"

If not, it might be easier to explain if we tweaked the command line synopsis to say that the command takes, after the destination repository, zero or more refspec or "tag <tag>". I dunno.

Show 14 quoted lines
> + 6. <src> may contain a * to indicate a simple pattern match.
> +    This works like a glob that matches any ref matching the pattern.
> +    There must be only one * in both the <src> and <dst>.
> +    It will map refs to the destination by replacing the * with the
> +    contents matched from the source. For example, `refs/heads/*:refs/heads/*`
> +    will push all branches.
> + 7. A refspec starting with ^ is a negative refspec.
> +    This specifies refs to exclude. A ref will be considered to
> +    match if it matches at least one positive refspec, and does not
> +    match any negative refspec. Negative refspecs can be pattern refspecs.
> +    They must only contain a <src>.
> +    Fully spelled out hex object names are also not supported.
> +    For example, `git push origin 'refs/heads/*' '^refs/heads/dev-*'`
> +    will push all branches except for those starting with `dev-`

Good. Somehow we have added the description of these to "git fetch" side, without updating "git push" side of the documentation.

> + 8. If `<src>` is empty, it deletes the <dst> ref from the remote
> +    repository. For example, `git push origin :dev` will
> +    delete the `dev` branch.

OK. This is specific to "push" (you do not delete your local branch by fetching :refs/heads/to-be-removed from elsewhere), so even if we wanted to unify the descriptions on both sides in the future, we'd need to be a bit careful around here.

> +    Deletions are always accepted without a leading `+` in the
> +    refspec (or `--force`), except when forbidden by configuration or hooks.

This can be read in two ways, making two opposing answers to this question possible: when forbidden, can you make a deletion accepted by giving a `+` in front?

"except when forbidden, deletions are accepted with or without `+`" might be less confusion-prone, but I dunno. I just wanted to make sure that it is clear that forcing or prepending `+` would not change anything when forbidden by configuration or hooks on the remote end.

But because you haven't mentioned that not all updates are allowed, this might be a bit out of place in this list. How about limiting this bullet point to only say that this is the syntax to use to delete a ref from the remote, and move the "deletions do not have to be forced and operations forbidden at the remote cannot be forced anyway" down, near the "Not all updates are allowed" below ...

> +    See `receive.denyDeletes` in linkgit:git-config[1] and `pre-receive` and
> +    `update` in linkgit:githooks[5].
... together with this?
Show 16 quoted lines
> + 9. If the refspec can't be expanded unambiguously, error
> +    out with an error indicating what was
> +    tried, and depending on the `advice.pushUnqualifiedRefname`
> +    configuration (see linkgit:git-config[1]) suggest what refs/
> +    namespace you may have wanted to push to.
> +
> ++
> +Not all updates are allowed: it depends on what kind of destination
> +you're pushing to. In the following rules "update" means any
> +modifications except deletes, which as noted above are treated differently.
> ++
> +All of these rules
> +can be overridden by adding the optional leading `+` to a refspec
>  (or using `--force` command line option). The only exception to this
>  is that no amount of forcing will make the `refs/heads/*` namespace
>  accept a non-commit object. Hooks and configuration can also override
Julia Evans· Aug 27, 2025, 13:10 UTC · re: Junio C Hamano · lore

Re: [PATCH 4/4] doc: git-push: rewrite refspec specification

Show 10 quoted lines
>> +`:<dst>` is optional.
>
> It may be technically true, but I am not sure if it is a good idea
> to say it here.  Without "when missing, <dst> is inferred with these
> rules", saying just "is optional" naturally invites a puzzlement:
> when do we need to supply it and for what?
>
> As you are going to say what happens when you omit it very soon, and
> you already have said with [:<dst>] that it is optional, perhaps you
> can scratch this sentence.

The reason I mentioned this early on is that when I read this for the first time it was quite confusing. Since `main` (or another branch name on its own) was the only push refspec I had experience using, it was disorienting to be told that the format was `<src>:<dst>`. It made me wonder if maybe `main` was not a refspec after all and I'd misunderstood the SYNOPSIS.

I know that I'm not alone in this: it's very common for Git users (even very experienced ones!) to learn the form `git push origin main`, but to otherwise not be familiar at all with the concept of a "refspec". So I'd like to do something here to help those folks connect their existing knowledge to the broader concept of a "refspec".

That said `:<dst> is optional` may not be necessary: I think the examples here accomplish more or less the same thing.

>>  +The format for a refspec is [+]<src>[:<dst>], for example `main`,
> > +`main:other`, or `HEAD^:refs/heads/main`.
Show 7 quoted lines
>> +`+` is optional and does the same thing as `--force`.
>
> Ditto; this one is less bad than the :<dst> thing, because at least
> it tells us what it means.  But we are going to talk about when an
> update is not allowed (we haven't even hinted that some updates may
> not be allowed yet) much later, "the same as `--force`" is probably
> a bit premature at this point in the documentation.

The reason I mentioned this so early is similar -- It's very common for experienced users to be familiar with the `--force` option, and so this is a quick way to explain to them what the `+` does.

As an aside, I noticed while reading this that it looks like the description of `--force` right now is not quite accurate, since the rule about pushing to tags is not "it must be an ancestor".

>--force::
>	Usually, the command refuses to update a remote ref that is
>	not an ancestor of the local ref used to overwrite it.

I'm going to think about whether there's a way to format the "rules for updates" so that they can be referred to from the `--force` section. Or maybe just move them to the `--force` option, and refer people there if they want to understand exactly when `--force` is required.

It's certainly much more common for users to use `--force` to force a push than to use `+`, from that perspective it would make more sense to document the rules next to `--force` than next to the description of `+`.

Show 5 quoted lines
>> +You can write a refspec using the fully expanded form (for
>> +example `main:refs/heads/main`) which specifies the exact source
>
> This example is not fully expanded.  refs/heads/main:refs/heads/main
> would be, though.
Makes sense, will change.
> I am not sure it is easier to read with numbered list.  It is not
> like these rules are applied in this order, or anything like that,
> right?

I had a similar concern. I'm still trying to figure out how to manage unordered lists, since lists with a `*` are formatted by AsciiDoc in a weird way in the terminal: there's a tab character after the • character which I don't understand the reason for.

Show 9 quoted lines
> A tangent.
> Is this a refspec you can write in .git/config, e.g.
>
> 	[remote "origin"]
> 		push = tag v1.0"
>
> If not, it might be easier to explain if we tweaked the command line
> synopsis to say that the command takes, after the destination
> repository, zero or more refspec or "tag <tag>".  I dunno.
I checked and it's not a valid refspec:

$ git push fatal: invalid refspec 'tag v1.0'

This list seems like a more natural place for that information than the synopsis though: the synopsis is already quite hard to read and we can't use it as the only place to communicate that information. I can add a note to say that 'tag v1.0' is technically not a refspec. Git already has enough weird exceptions like that that I don't think it'll be too jarring.

> Perhaps move it down together with the "push void to remove"
> at the top of the list?
I'll also move it down.
> Good.  Somehow we have added the description of these to "git fetch"
> side, without updating "git push" side of the documentation.

Yes, I copied this part from the `git fetch` documention after checking that they worked with `git push` as well.

Show 18 quoted lines
>> +    Deletions are always accepted without a leading `+` in the
>> +    refspec (or `--force`), except when forbidden by configuration or hooks.
>
> This can be read in two ways, making two opposing answers to this
> question possible: when forbidden, can you make a deletion accepted
> by giving a `+` in front?
> "except when forbidden, deletions are accepted with or without `+`"
> might be less confusion-prone, but I dunno.  I just wanted to make
> sure that it is clear that forcing or prepending `+` would not
> change anything when forbidden by configuration or hooks on the
> remote end.
> 
> But because you haven't mentioned that not all updates are allowed,
> this might be a bit out of place in this list.  How about limiting
> this bullet point to only say that this is the syntax to use to
> delete a ref from the remote, and move the "deletions do not have to
> be forced and operations forbidden at the remote cannot be forced
> anyway" down, near the "Not all updates are allowed" below ...
Will do, that's much cleaner.
>> +    See `receive.denyDeletes` in linkgit:git-config[1] and `pre-receive` and
>> +    `update` in linkgit:githooks[5].
>
> ... together with this?
This makes sense.
- Julia
D. Ben Knoble· Aug 28, 2025, 19:28 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH 4/4] doc: git-push: rewrite refspec specification

Thanks for the docs updates! A few nits below, but this looks nice to me :)

On Tue, Aug 26, 2025 at 4:40 PM Julia Evans via GitGitGadget <gitgitgadget@gmail.com> wrote:

Show 14 quoted lines
>
> From: Julia Evans <julia@jvns.ca>
>
> - Originally it said that a refspec was `+<src>:<dst>`, but then later
>   contradicted itself by saying that the `:<dst>` is optional.
>   Mention that `:<dst>` is optional much earlier.
> - Put the complex sets of rules about different refspec forms
>   in lists instead of in long paragraphs of prose
> - Add examples for the various types of refspecs
>   (negative, deletion, pattern, etc)
> - Previously `*` and `^` were not mentioned, mention them
> - Explain what `+` does earlier
> - Remove "might be added in the future" (it's a given that software
>   might change in the future)
Excellent ideas!
Show 13 quoted lines
> diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
> index 0232195515c9..78d433c60c51 100644
> --- a/Documentation/git-push.adoc
> +++ b/Documentation/git-push.adoc
> @@ -57,77 +57,74 @@ OPTIONS[[OPTIONS]]
> +The format for a refspec is [+]<src>[:<dst>], for example `main`,
> +`main:other`, or `HEAD^:refs/heads/main`.
> ++
> +The `<src>` is often the name of the local branch to push, but it can be
> +any arbitrary "SHA-1 expression" (see linkgit:gitrevisions[7]).
> ++
> +The `<dst>` determines what to update on the remote side. It must be the
> +name of a branch, tag, or other ref, not an arbitrary expression.

A welcome (to me) simplification from the original paragraph, especially if we don't lose the original content but rearrange it better :)

> +`:<dst>` is optional.
Here…
> ++
> +`+` is optional and does the same thing as `--force`.
> ++
…and here, I find it odd to start sentences with punctuation if we can avoid it.
Show 20 quoted lines
> +You can write a refspec using the fully expanded form (for
> +example `main:refs/heads/main`) which specifies the exact source
> +and destination, or with a shorter form (for example `main` or
> +`main:other`). Here are the rules for how refspecs are expanded,
> +as well as various other special refspec forms:
> ++
> + 1. `<src>` without a `:<dst>` means to update the same ref as the
> +       `<src>`, unless the `remote.<repository>.push` configuration specifies a
> +       different <dst>. For example, if `main` is a branch, then the refspec
> +    `main` expands to `main:refs/heads/main`.
> + 2. If <dst> unambiguously refers to a ref on the <repository> remote,
> +    then expand it to that ref. For example, if `v1.0` is a tag on the
> +    remote, then `HEAD:v1.0` expands to `HEAD:refs/tags/v1.0`.
> + 3. If <src> resolves to a ref starting with refs/heads/ or refs/tags/,
> +    then prepend that to <dst>. For example, if `main` is a branch, then
> +    `main:other` expands to `main:refs/heads/other`
> + 4. The special refspec `:` (or `+:` to allow non-fast-forward updates)
> +    directs Git to push "matching" branches: for every branch that exists on
> +    the local side, the remote side is updated if a branch of the same name
> +    already exists on the remote side.

I'm not 100% sure this belongs as an item in an ordered list here, since it implies (structurally) something about the order of possible expansions tried. But the introduction to the list does say "rules [and] special refspec forms"… Hm. Maybe it's worth splitting the special ones out? idk.

I see Junio mentioned something similar.
Show 5 quoted lines
> + 5. `tag <tag>` expands to `refs/tags/<tag>:refs/tags/<tag>`.
> + 6. <src> may contain a * to indicate a simple pattern match.
> +    This works like a glob that matches any ref matching the pattern.
> +    There must be only one * in both the <src> and <dst>.
> +    It will map refs to the destination by replacing the * with the
Should src/dst/* have backticks here? I'm not sure.
> +    contents matched from the source. For example, `refs/heads/*:refs/heads/*`
> +    will push all branches.
> + 7. A refspec starting with ^ is a negative refspec.
Ditto the "^"
Show 7 quoted lines
> +    This specifies refs to exclude. A ref will be considered to
> +    match if it matches at least one positive refspec, and does not
> +    match any negative refspec. Negative refspecs can be pattern refspecs.
> +    They must only contain a <src>.
> +    Fully spelled out hex object names are also not supported.
> +    For example, `git push origin 'refs/heads/*' '^refs/heads/dev-*'`
> +    will push all branches except for those starting with `dev-`

I learned something new today! This isn't in the manual I have for 2.48.1 or 2.51.x locally. Thanks! [Junio mentions it's on the fetch side, which I see now]

> + 8. If `<src>` is empty, it deletes the <dst> ref from the remote
Backticks for dst ;)
> +    repository. For example, `git push origin :dev` will
> +    delete the `dev` branch.
> +    Deletions are always accepted without a leading `+` in the
> +    refspec (or `--force`), except when forbidden by configuration or hooks.

Maybe "except when forbidden on the remote by…" ? (This came from the original and does not need tweaked in this series, though.)

Show 7 quoted lines
> +    See `receive.denyDeletes` in linkgit:git-config[1] and `pre-receive` and
> +    `update` in linkgit:githooks[5].
> + 9. If the refspec can't be expanded unambiguously, error
> +    out with an error indicating what was
> +    tried, and depending on the `advice.pushUnqualifiedRefname`
> +    configuration (see linkgit:git-config[1]) suggest what refs/
> +    namespace you may have wanted to push to.
Wrapping looks strange to me here.
Show 8 quoted lines
> +
> ++
> +Not all updates are allowed: it depends on what kind of destination
> +you're pushing to. In the following rules "update" means any
> +modifications except deletes, which as noted above are treated differently.
> ++
> +All of these rules
> +can be overridden by adding the optional leading `+` to a refspec
Ditto.
Show 34 quoted lines
>  (or using `--force` command line option). The only exception to this
>  is that no amount of forcing will make the `refs/heads/*` namespace
>  accept a non-commit object. Hooks and configuration can also override
> @@ -135,18 +132,21 @@ or amend these rules, see e.g. `receive.denyNonFastForwards` in
>  linkgit:git-config[1] and `pre-receive` and `update` in
>  linkgit:githooks[5].
>  +
> -Pushing an empty <src> allows you to delete the <dst> ref from the
> -remote repository. Deletions are always accepted without a leading `+`
> -in the refspec (or `--force`), except when forbidden by configuration
> -or hooks. See `receive.denyDeletes` in linkgit:git-config[1] and
> -`pre-receive` and `update` in linkgit:githooks[5].
> -+
> -The special refspec `:` (or `+:` to allow non-fast-forward updates)
> -directs Git to push "matching" branches: for every branch that exists on
> -the local side, the remote side is updated if a branch of the same name
> -already exists on the remote side.
> -+
> -`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
> +1. If the destination is a **branch** (`refs/heads/*`): the source must
> +   be a commit object, and only fast-forward updates are allowed.
> +2. If the destination is a **tag** (`refs/tags/*`):  the source can
> +   be any object (as commits, trees and blobs can be tagged), and any
> +   updates to them will be rejected.
> +3. For destinations outside of `refs/{tags,heads}/*`:
> +   * If the source is a tree or blob object, any updates will be rejected
> +   * If the source is a tag or commit object, any fast-forward update
> +     is allowed, even in cases where what's being fast-forwarded is not a
> +     commit, but a tag object which happens to point to a new commit which
> +     is a fast-forward of the commit the last tag (or commit) it's
> +     replacing. Replacing a tag with an entirely different tag is also
> +     allowed, if it points to the same commit, as well as pushing a peeled
> +     tag, i.e. pushing the commit that existing tag object points to, or a
> +     new tag object which an existing commit points to.
I didn't close-read this bit, but it seems reasonable.
-- 
D. Ben Knoble
Julia Evans via GitGitGadget· Sep 12, 2025, 18:55 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v2 0/4] doc: git-push: clarify DESCRIPTION section & refspec definition

I surveyed 16 Git users about the git push man page. Here's a rewrite of the DESCRIPTION section and the definition of <refspec> based on the feedback. The goal is to clarify it while communicating the same information. The most common piece of feedback was that folks didn't understand what the term "ref" means. Most of the users who said they did not understand the term "ref" have been using Git for 10+ years.

The rewrite of the <refspec> section is more invasive than I usually prefer: I've tried to keep as much of the original text as possible, but if there are too many issues with it then I'll drop that patch from this series.

changes in v2:
 * The biggest change is to add a new UPSTREAM BRANCHES section to explain
   what an upstream is
 * Drop the "refspec" changes from this patch series, I've made revisions to
   them based on the comments here but I felt like this was getting too big.
 * Added some backticks `` that I'd missed, from Ben's review
 * From Junio's review, "The current branch must have a configured upstream
   with the same name, so this will fail when pushing a new branch" was not
   true, so replace it with a less detailed but hopefully true statement.
   After a very long conversation with Ben I realized that actually
   push.default=simple's behaviour is not really that simple (perhaps I
   should think of it as more "safe" than "simple", since "current" seems
   simpler), so it's more realistic to refer any questions to the
   CONFIGURATION section which describes the behaviour in more detail.
 * Rewrite all the commits to explain the problem they're trying to solve &
   thinking behind them in more detail. Let me know if I added too much /
   not enough detail.
Julia Evans (4):
  doc: git-push: clarify intro
  doc: add an UPSTREAM BRANCHES section to pull/push/fetch
  doc: git-push: clarify "where to push"
  doc: git-push: clarify "what to push"
 Documentation/git-fetch.adoc                  |  2 +-
 Documentation/git-pull.adoc                   |  2 +-
 Documentation/git-push.adoc                   | 43 ++++++++++---------
 ...motes.adoc => urls-remotes-upstreams.adoc} | 41 ++++++++++++++++--
 4 files changed, 62 insertions(+), 26 deletions(-)
 rename Documentation/{urls-remotes.adoc => urls-remotes-upstreams.adoc} (63%)
base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1964%2Fjvns%2Fclarify-push-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1964/jvns/clarify-push-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/1964
Range-diff vs v1:
 1:  2fa98fb5ca ! 1:  270edd2b00 doc: git-push: update intro
     @@ Metadata
      Author: Julia Evans <julia@jvns.ca>
      
       ## Commit message ##
     -    doc: git-push: update intro
     +    doc: git-push: clarify intro
      
     -    - Users don't understand what a "ref" is, expand it
     -    - Remove "complete the given refs" (that phrase is confusing to many
     -      users, and it's obvious that pushing a branch involves sending the
     -      new code)
     -    - Move down the reference to hooks, it's less important than the
     -      command's basic usage
     +    From user feedback, 5 users are unsure what "ref" and/or "objects" means
     +    in this context. 3 users said they don't know what "complete the refs"
     +    means.
     +
     +    Many users also commented that receive hooks do not seem like the most
     +    important thing to know about `git push`, and that this information
     +    should not be the second sentence in the man page.
     +
     +    Use more familiar language to make it more accessible to users who do
     +    not know what a "ref" is and move the "hooks" comment to the end.
      
          Signed-off-by: Julia Evans <julia@jvns.ca>
      
 -:  ---------- > 2:  0ec629d403 doc: add an UPSTREAM BRANCHES section to pull/push/fetch
 2:  36112c30bc ! 3:  374740c678 doc: git-push: clarify "where to push"
     @@ Metadata
       ## Commit message ##
          doc: git-push: clarify "where to push"
      
     -    Signed-off-by: Julia Evans <julia@jvns.ca>
     -
          Be clearer about what we're describing ("which repository" instead of
          "what to push"), and start with a positive "try X, then Y, then Z"
          instead of a negative ("if X is not specified..").
     @@ Documentation/git-push.adoc: DESCRIPTION
      -configuration is missing, it defaults to 'origin'.
      +To decide which repository to push to, Git uses the `<repository>`
      +argument (for example `git push dev`), then if that's not specified the
     -+`branch.*.remote` configuration for the current branch, and then defaults
     ++upstream configuration for the current branch, and then defaults
      +to `origin`.
       
       When the command line does not specify what to push with `<refspec>...`
 3:  ac554cbe75 ! 4:  59732f1e47 doc: git-push: clarify "what to push"
     @@ Metadata
       ## Commit message ##
          doc: git-push: clarify "what to push"
      
     -    - Be more explicit about what we're describing ("which branches" instead
     -      of "what to push")
     -    - Split out the ways to specify which branches into a numbered list,
     -      since there are 5 different ways to specify it and it's a lot to parse
     -      in paragraph form
     -    - The explanation of "push.default=simple" is confusing to some users,
     -      use an explanation more similar to the one in `man git-config`
     -    - Mention the most common case where push.default=simple is likely to
     -      fail, and how to handle it
     +    From user feedback: 6 users says they found the "what to push"
     +    paragraphs confusing, for many different reasons, including:
     +
     +    * what does "..." in <refspec>... mean?
     +    * "consult XXX configuration" is hard to parse
     +    * it refers to the `git-config` man page even though the config
     +      information for `git push` is included in this man page under
     +      CONFIGURATION
     +    * the default ("push to a branch with the same name") is what they use
     +      99% of the time, they would have expected it to appear earlier instead
     +      of at the very end
     +    * not understanding what the term "upstream" means in Git
     +      ("are branches tracked by some system besides their names?"")
     +
     +    Address all of these by using a numbered "in order of precedence" list
     +    (similar to the previous commit), by giving a little bit of context
     +    around "upstream branch": it's something that you may have to set
     +    explicitly, and referring to the new UPSTREAM BRANCHES section.
     +
     +    The default behaviour is still discussed pretty late but it should be
     +    easier to skim now to get to the relevant information.
      
          Signed-off-by: Julia Evans <julia@jvns.ca>
      
       ## Documentation/git-push.adoc ##
      @@ Documentation/git-push.adoc: argument (for example `git push dev`), then if that's not specified the
     - `branch.*.remote` configuration for the current branch, and then defaults
     + upstream configuration for the current branch, and then defaults
       to `origin`.
       
      -When the command line does not specify what to push with `<refspec>...`
     @@ Documentation/git-push.adoc: argument (for example `git push dev`), then if that
      -the default `<refspec>` by consulting `remote.*.push` configuration,
      -and if it is not found, honors `push.default` configuration to decide
      -what to push (See linkgit:git-config[1] for the meaning of `push.default`).
     -+To decide which branches, tags, or other refs to push, Git uses
     -+(in order of precedence):
     -+
     -+1. The <refspec> argument(s) (for example `main` in `git push origin main`)
     -+   or the `--all`, `--mirror`, or `--tags` options
     -+2. The `remote.*.push` configuration for the current branch
     -+3. The `push.default` configuration (See linkgit:git-config[1] for
     -+   the meaning of `push.default`).
     - 
     - When neither the command-line nor the configuration specifies what to
     +-
     +-When neither the command-line nor the configuration specifies what to
      -push, the default behavior is used, which corresponds to the `simple`
      -value for `push.default`: the current branch is pushed to the
      -corresponding upstream branch, but as a safety measure, the push is
      -aborted if the upstream branch does not have the same name as the
      -local one.
     -+push, the current branch is pushed to the branch with the same name
     -+on the remote. The current branch must have a configured upstream with
     -+the same name, so this will fail when pushing a new branch.
     -+You can run `git push -u <repository> <current-branch>`
     -+to configure the upstream.
     ++To decide which branches, tags, or other refs to push, Git uses
     ++(in order of precedence):
     ++
     ++1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
     ++   or the `--all`, `--mirror`, or `--tags` options
     ++2. The `remote.*.push` configuration for the repository being pushed to
     ++3. The `push.default` configuration. The default is `push.default=simple`,
     ++   which will push to a branch with the same name as the current branch.
     ++   See the CONFIGURATION section below for more on `push.default`.
     ++
     ++As a safety measure, `git push` may fail if you haven't set an upstream
     ++for the current branch, depending on what `push.default` is set to.
     ++See the UPSTREAM BRANCHES section below for more on how to set and
     ++use upstreams.
       
       You can make interesting things happen to a repository
       every time you push into it, by setting up 'hooks' there.  See
 4:  72114133aa < -:  ---------- doc: git-push: rewrite refspec specification
-- 
gitgitgadget
Julia Evans via GitGitGadget· Sep 12, 2025, 18:55 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v2 1/4] doc: git-push: clarify intro

From: Julia Evans <julia@jvns.ca>

From user feedback, 5 users are unsure what "ref" and/or "objects" means in this context. 3 users said they don't know what "complete the refs" means.

Many users also commented that receive hooks do not seem like the most important thing to know about `git push`, and that this information should not be the second sentence in the man page.

Use more familiar language to make it more accessible to users who do not know what a "ref" is and move the "hooks" comment to the end.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)
Show changes to Documentation/git-push.adoc +5 −6
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index d1978650d6..e73b64f61f 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -19,12 +19,8 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Updates remote refs using local refs, while sending objects
-necessary to complete the given refs.
-
-You can make interesting things happen to a repository
-every time you push into it, by setting up 'hooks' there.  See
-documentation for linkgit:git-receive-pack[1].
+Updates one or more branches, tags, or other references in a remote
+repository from your local repository.
 
 When the command line does not specify where to push with the
 `<repository>` argument, `branch.*.remote` configuration for the
@@ -44,6 +40,9 @@ corresponding upstream branch, but as a safety measure, the push is
 aborted if the upstream branch does not have the same name as the
 local one.
 
+You can make interesting things happen to a repository
+every time you push into it, by setting up 'hooks' there.  See
+documentation for linkgit:git-receive-pack[1].
 
 OPTIONS[[OPTIONS]]
 ------------------
-- 
gitgitgadget
Junio C Hamano· Sep 12, 2025, 20:54 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v2 1/4] doc: git-push: clarify intro

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 5 quoted lines
> From: Julia Evans <julia@jvns.ca>
>
> From user feedback, 5 users are unsure what "ref" and/or "objects" means
> in this context. 3 users said they don't know what "complete the refs"
> means.

Well, "this concept I do not understand" from many users is not necessarily mean that the concept does not have to be taught.

Show 5 quoted lines
> -Updates remote refs using local refs, while sending objects
> -necessary to complete the given refs.
>
> +Updates one or more branches, tags, or other references in a remote
> +repository from your local repository.

This is a very good rewrite of the first half of the sentence. Complete loss of the latter is a bit disturbing.

    Send data that records commits, directories, and files
    (collectively called "objects"), and update branches, tags and
    other references at the remote repository, to make newer part of
    the history available there.
or something?
Show 10 quoted lines
> @@ -44,6 +40,9 @@ corresponding upstream branch, but as a safety measure, the push is
>  aborted if the upstream branch does not have the same name as the
>  local one.
>  
> +You can make interesting things happen to a repository
> +every time you push into it, by setting up 'hooks' there.  See
> +documentation for linkgit:git-receive-pack[1].
>  
>  OPTIONS[[OPTIONS]]
>  ------------------

Moving the description of the secondary effect down like this is a welcome change.

The original had two blank lines to separate the previous section and the subsequent OPTIONS section, but now we have only one. It would not make a difference in the rendered output, but having a blank lines between paragraphs and two blank lines between sections, if done consistently, would help reading the documentation in the source form.

Thanks.
Julia Evans· Sep 15, 2025, 20:00 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 1/4] doc: git-push: clarify intro

> Well, "this concept I do not understand" from many users is not
> necessarily mean that the concept does not have to be taught.

That's true. I'll try to explain in more detail why I think terms can be omitted (or why they can't!) in the future. Here we're talking about two terms: refs and objects.

Re "refs": I think "refs" is pretty relevant to `git push`, which is why I left it in (as "or other references", to give readers a hint that a branch is a type of ref/reference).

Re "objects": I can't think right now of a common reason why it would be useful to understand the details of how Git's object database works in the context of "git push", do you have an example? I think `git show` is a much better example of a command where the term "object" is relevant, because you can use `git show` to show blob objects.

Show 15 quoted lines
>> -Updates remote refs using local refs, while sending objects
>> -necessary to complete the given refs.
>>
>> +Updates one or more branches, tags, or other references in a remote
>> +repository from your local repository.
>
> This is a very good rewrite of the first half of the sentence.
> Complete loss of the latter is a bit disturbing.
>
>     Send data that records commits, directories, and files
>     (collectively called "objects"), and update branches, tags and
>     other references at the remote repository, to make newer part of
>     the history available there.
>
> or something?
Will try this:
    Updates one or more branches, tags, or other references in a remote
    repository from your local repository, and sends all necessary data in
   those branches or tags that isn't already on the remote.

The goal there is to make sure the reader knows that git push may need to send a significant amount of data, depending on what's in the new commits you're pushing.

Show 8 quoted lines
>>  OPTIONS[[OPTIONS]]
>>  ------------------
>
> Moving the description of the secondary effect down like this is a
> welcome change.
>
> The original had two blank lines to separate the previous section
> and the subsequent OPTIONS section, but now we have only one.
Will fix.
Junio C Hamano· Sep 16, 2025, 01:44 UTC · re: Julia Evans · lore

Re: [PATCH v2 1/4] doc: git-push: clarify intro

"Julia Evans" <julia@jvns.ca> writes:
> Re "refs": I think "refs" is pretty relevant to `git push`, which is why I left it in
> (as "or other references", to give readers a hint that a branch is a type
> of ref/reference).
I have (and I didn't have) no issues with "refs" -> "references".
Show 9 quoted lines
> Will try this:
>
>     Updates one or more branches, tags, or other references in a remote
>     repository from your local repository, and sends all necessary data in
>     those branches or tags that isn't already on the remote.
>
> The goal there is to make sure the reader knows that git push may need to
> send a significant amount of data, depending on what's in the new commits
> you're pushing.

Yes. I do not partculary see the point of deliberately trying to be vague by saying "data" (in "all necessary data") instead of "tags, commits, trees, and blobs (collectively known as objects), but I agree with the stated goal here.

Julia Evans· Sep 16, 2025, 18:46 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 1/4] doc: git-push: clarify intro

Show 14 quoted lines
>> Will try this:
>>
>>     Updates one or more branches, tags, or other references in a remote
>>     repository from your local repository, and sends all necessary data in
>>     those branches or tags that isn't already on the remote.
>>
>> The goal there is to make sure the reader knows that git push may need to
>> send a significant amount of data, depending on what's in the new commits
>> you're pushing.
>
> Yes.  I do not partculary see the point of deliberately trying to be
> vague by saying "data" (in "all necessary data") instead of "tags,
> commits, trees, and blobs (collectively known as objects), but I
> agree with the stated goal here.

What we're trying to prevent here is readers getting distracted by trying to learn concepts which are not necessary to understand how `git push` works. For example, one user commented:

> I had to look up what the term "object" meant...

It's not necessary to know what an "object" is to understand how to use `git push` (though if you have an example of why it is necessary, I would love to hear it!) If it's not necessary to understand the command, readers should not feel like they have to look it up to understand its documentation.

I think "..., and sends all necessary commits or other objects that aren't already on the remote." might work if we want to add more detail, since it gives users a hint that maybe they can ignore the "or other objects" part if they're not sure what an "object" is.

Ben Knoble· Sep 16, 2025, 20:38 UTC · re: Julia Evans · lore

Re: [PATCH v2 1/4] doc: git-push: clarify intro

Show 6 quoted lines
> Le 16 sept. 2025 à 14:46, Julia Evans <julia@jvns.ca> a écrit :
> 
> I think "..., and sends all necessary commits or other objects that aren't
> already on the remote." might work if we want to add more detail, since it
> gives users a hint that maybe they can ignore the  "or other objects"  part if
> they're not sure what an "object" is.
Nit, without wading into the above discussion: shouldn’t that be « and other objects »?
Junio C Hamano· Sep 16, 2025, 21:59 UTC · re: Ben Knoble · lore

Re: [PATCH v2 1/4] doc: git-push: clarify intro

Ben Knoble <ben.knoble@gmail.com> writes:
Show 8 quoted lines
>> Le 16 sept. 2025 à 14:46, Julia Evans <julia@jvns.ca> a écrit :
>> 
>> I think "..., and sends all necessary commits or other objects that aren't
>> already on the remote." might work if we want to add more detail, since it
>> gives users a hint that maybe they can ignore the  "or other objects"  part if
>> they're not sure what an "object" is.
>
> Nit, without wading into the above discussion: shouldn’t that be « and other objects »?

You could push a tag that points at a blob, so it is possible that the push transfers only "other objects", but "necessary commits and other objects" would naturally cover the case where the number of necessary commits is zero ;-), so I tend to agree that *and* would read better in that sentence.

But if we really want to do the progressive disclosure, I am OK with the idea that hiding the details behind a vague words like "transfer data necessary for updated branches" without saying what these data are would work OK.

Thanks.
Junio C Hamano· Sep 17, 2025, 18:42 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 1/4] doc: git-push: clarify intro

Junio C Hamano <gitster@pobox.com> writes:
Show 22 quoted lines
> "Julia Evans" <julia@jvns.ca> writes:
>
>> Re "refs": I think "refs" is pretty relevant to `git push`, which is why I left it in
>> (as "or other references", to give readers a hint that a branch is a type
>> of ref/reference).
>
> I have (and I didn't have) no issues with "refs" -> "references".
>
>> Will try this:
>>
>>     Updates one or more branches, tags, or other references in a remote
>>     repository from your local repository, and sends all necessary data in
>>     those branches or tags that isn't already on the remote.
>>
>> The goal there is to make sure the reader knows that git push may need to
>> send a significant amount of data, depending on what's in the new commits
>> you're pushing.
>
> Yes.  I do not partculary see the point of deliberately trying to be
> vague by saying "data" (in "all necessary data") instead of "tags,
> commits, trees, and blobs (collectively known as objects), but I
> agree with the stated goal here.
Let me change my mind here.

If you are trying to avoid overwhelming the readers by carefully trying not to write things that do not have to be said at each point in the teaching, I do agree that the deliberate vagueness I mentioned above is a good idea. You seem to have better "taste" of knowing what the right amount of detail to give, a lot better than I do.

Please keep these goodness coming.
Thanks.
Julia Evans· Sep 18, 2025, 14:20 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 1/4] doc: git-push: clarify intro

Show 10 quoted lines
> Let me change my mind here.
>
> If you are trying to avoid overwhelming the readers by carefully
> trying not to write things that do not have to be said at each point
> in the teaching, I do agree that the deliberate vagueness I
> mentioned above is a good idea.  You seem to have better "taste" of
> knowing what the right amount of detail to give, a lot better than I
> do.
>
> Please keep these goodness coming.

Thanks so much for the encouragement, it really helps a lot. I've appreciated your detailed reviews.

let's keep going!
- Julia
Julia Evans via GitGitGadget· Sep 12, 2025, 18:55 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

From: Julia Evans <julia@jvns.ca>

From user feedback: one user mentioned that they don't know what the term "upstream branch" means. As far as I can tell, the most complete description is under the `--track` option in `git branch`. Upstreams are an important concept in Git and the `git branch` man page is not an obvious place for that information to live.

There's also a very terse description of "upstream branch" in the glossary that's missing a lot of key information, like the fact that the upstream is used by `git status` and `git pull`, as well as a description in `git-config` in `branch.<name>.remote` which doesn't explain the relationship to `git status` either.

Since the `git pull`, `git push`, and `git fetch` man pages already include sections on REMOTES and the syntax for URLs, add a section on UPSTREAM BRANCHES to `urls-remotes.adoc` and rename it to `urls-remotes-upstreams.adoc`. That's an awkward name but at least it's clear what's in the file.

In the new UPSTREAM BRANCHES section, cover the various ways that upstreams branches are automatically set in Git, since users may mistakenly think that their branch does not have an upstream branch if they didn't explicitly set one.

A terminology note: Git uses two terms for this concept:
- "tracking" as in "the current branch is _tracking_ some remote"
  or the `--track` option to `git branch`
- "upstream" or "upstream branch", as in `git push --set-upstream`.
  This term is also used in the `git rebase` man page to refer to the
  first argument to `git rebase`, as well as in `git pull` to refer to
  the branch which is going to be merged into the current branch ("merge
  the upstream branch into the current branch")

Use "upstream branch" as a heading for this concept even though the term "upstream branch" is not always used strictly in the sense of "the tracking information for the current branch". "Upstream" is used much more often than "tracking" in the Git docs to refer to this concept and the goal is to help users understand the docs.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-fetch.adoc                  |  2 +-
 Documentation/git-pull.adoc                   |  2 +-
 Documentation/git-push.adoc                   |  2 +-
 ...motes.adoc => urls-remotes-upstreams.adoc} | 41 +++++++++++++++++--
 4 files changed, 41 insertions(+), 6 deletions(-)
 rename Documentation/{urls-remotes.adoc => urls-remotes-upstreams.adoc} (63%)
Show changes to 5 files +41 −6

Documentation/git-fetch.adoc, Documentation/git-pull.adoc, Documentation/git-push.adoc, Documentation/urls-remotes.adoc, Documentation/urls-remotes-upstreams.adoc

diff --git a/Documentation/git-fetch.adoc b/Documentation/git-fetch.adoc
index 16f5d9d69a..6402b3d69e 100644
--- a/Documentation/git-fetch.adoc
+++ b/Documentation/git-fetch.adoc
@@ -52,7 +52,7 @@ include::pull-fetch-param.adoc[]
 	Read refspecs, one per line, from stdin in addition to those provided
 	as arguments. The "tag <name>" format is not supported.
 
-include::urls-remotes.adoc[]
+include::urls-remotes-upstreams.adoc[]
 
 
 CONFIGURED REMOTE-TRACKING BRANCHES[[CRTB]]
diff --git a/Documentation/git-pull.adoc b/Documentation/git-pull.adoc
index 3f4ecc4730..6cc329895d 100644
--- a/Documentation/git-pull.adoc
+++ b/Documentation/git-pull.adoc
@@ -140,7 +140,7 @@ include::fetch-options.adoc[]
 
 include::pull-fetch-param.adoc[]
 
-include::urls-remotes.adoc[]
+include::urls-remotes-upstreams.adoc[]
 
 include::merge-strategies.adoc[]
 
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index e73b64f61f..ec396b4cf2 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -431,7 +431,7 @@ further recursion will occur. In this case, "only" is treated as "on-demand".
 --ipv6::
 	Use IPv6 addresses only, ignoring IPv4 addresses.
 
-include::urls-remotes.adoc[]
+include::urls-remotes-upstreams.adoc[]
 
 OUTPUT
 ------
diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes-upstreams.adoc
similarity index 63%
rename from Documentation/urls-remotes.adoc
rename to Documentation/urls-remotes-upstreams.adoc
index 9b10151198..1e9c56dc5f 100644
--- a/Documentation/urls-remotes.adoc
+++ b/Documentation/urls-remotes-upstreams.adoc
@@ -91,6 +91,41 @@ git push uses:
 	HEAD:refs/heads/<head>
 ------------
 
-
-
-
+UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
+--------------------------------------
+
+Branches in Git can optionally have an upstream remote branch.
+Git defaults to using the upstream branch for remote operations, for example:
+
+* It's the default for `git pull` or `git fetch` with no arguments
+* It's sometimes the default for `git push` with no arguments. See the
+  `push.default` section of linkgit:git-config[1] for the details.
+* `git status` and `git branch -v` will show the
+  relationship between the current branch and the upstream,
+  for example "Your branch is up to date with origin/main"
+
+The upstream is stored in `.git/config`, in the "remote" and "merge"
+fields. For example, if `main`'s upstream is `origin/main`:
+
+```
+[branch "main"]
+   remote = origin
+   merge = refs/heads/main
+```
+
+You can set an upstream branch explicitly with
+`git push --set-upstream <remote> <branch>` or `git branch --track`,
+but Git will often automatically set the upstream for you, for example:
+
+* When you clone a repository, Git will automatically set the upstream
+  for the default branch.
+* If you have the `push.autoSetupRemote` configuration option set,
+  `git push` will automatically set the upstream the first time you push
+  a branch.
+* Checking out a remote-tracking branch with `git checkout <branch>`
+  will automatically create a local branch with that name and set
+  the upstream to the remote branch.
+
+[NOTE]
+Upstream branches are sometimes referred to as "tracking information",
+as in "set the branch's tracking information".
-- 
gitgitgadget
Junio C Hamano· Sep 12, 2025, 21:17 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
> diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes-upstreams.adoc
> similarity index 63%
> rename from Documentation/urls-remotes.adoc
> rename to Documentation/urls-remotes-upstreams.adoc

I'd personally recommend against making this rename, as we would likely add more kinds of information later, just like we are adding one now with this patch, than we would remove any. For example, we may find that this is a good place to also touch upon a triangular workflow, where you would track your upstream by pulling from there, and then you publish your work to your own remote that others can pull from (and the expectation is that your upstream would pull from that publishing repository of yours, which complets the triangle), instead of leaving it vague in the `git push` description as "See push.default and git-config for details" in the section we are adding in this patch. We will not rename the file again to Documentation/urls-remotes-upstreams-triangles.adoc when that happens ;-).

Show 22 quoted lines
> index 9b10151198..1e9c56dc5f 100644
> --- a/Documentation/urls-remotes.adoc
> +++ b/Documentation/urls-remotes-upstreams.adoc
> @@ -91,6 +91,41 @@ git push uses:
>  	HEAD:refs/heads/<head>
>  ------------
>  
> -
> -
> -
> +UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
> +--------------------------------------
> +
> +Branches in Git can optionally have an upstream remote branch.
> +Git defaults to using the upstream branch for remote operations, for example:
> +
> +* It's the default for `git pull` or `git fetch` with no arguments
> +* It's sometimes the default for `git push` with no arguments. See the
> +  `push.default` section of linkgit:git-config[1] for the details.
> +* `git status` and `git branch -v` will show the
> +  relationship between the current branch and the upstream,
> +  for example "Your branch is up to date with origin/main"

Although I would rewrite the second one (i.e. "push") for clarity, to be more explicit that we are discussing only about centralized workflow in this description, the above is a good write up. Here is my version, including the push one:

    It is the default for `git fetch` (hence `git pull`) and `git
    push` when no arguments are given, and you are using the
    centralized workflow.  To use a triangular workflow, in which
    you fetch/pull from your upstream but you push your work to a
    third repository, `git push` can be configured to push to
    somewhere other than your upstream remote branch.
    Various commands, including `git status`, `git checkout`, and
    `git branch -v`, reminds you how many commits you have on top of
    your upstream, and how many commits they added to your upstream
    since your branch has forked from it.

When we would upgrade this file with a more detailed description of the triangular workflow, we'd remove the "To use a triangular..." sentence from above, and leave it to the new section.

Show 25 quoted lines
> +The upstream is stored in `.git/config`, in the "remote" and "merge"
> +fields. For example, if `main`'s upstream is `origin/main`:
> +
> +```
> +[branch "main"]
> +   remote = origin
> +   merge = refs/heads/main
> +```
> +
> +You can set an upstream branch explicitly with
> +`git push --set-upstream <remote> <branch>` or `git branch --track`,
> +but Git will often automatically set the upstream for you, for example:
> +
> +* When you clone a repository, Git will automatically set the upstream
> +  for the default branch.
> +* If you have the `push.autoSetupRemote` configuration option set,
> +  `git push` will automatically set the upstream the first time you push
> +  a branch.
> +* Checking out a remote-tracking branch with `git checkout <branch>`
> +  will automatically create a local branch with that name and set
> +  the upstream to the remote branch.
> +
> +[NOTE]
> +Upstream branches are sometimes referred to as "tracking information",
> +as in "set the branch's tracking information".

Everything you wrote here looks like a great addition. Nicely done.

Julia Evans· Sep 15, 2025, 20:19 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Fri, Sep 12, 2025, at 5:17 PM, Junio C Hamano wrote:
Show 8 quoted lines
> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
>> diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes-upstreams.adoc
>> similarity index 63%
>> rename from Documentation/urls-remotes.adoc
>> rename to Documentation/urls-remotes-upstreams.adoc
>
> I'd personally recommend against making this rename
Great, it felt awkward to me too. Will leave it as is.
Show 24 quoted lines
>> +UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
>> +--------------------------------------
>> +
>> +Branches in Git can optionally have an upstream remote branch.
>> +Git defaults to using the upstream branch for remote operations, for example:
>> +
>> +* It's the default for `git pull` or `git fetch` with no arguments
>> +* It's sometimes the default for `git push` with no arguments. See the
>> +  `push.default` section of linkgit:git-config[1] for the details.
>> +* `git status` and `git branch -v` will show the
>> +  relationship between the current branch and the upstream,
>> +  for example "Your branch is up to date with origin/main"
>
> Although I would rewrite the second one (i.e. "push") for clarity,
> to be more explicit that we are discussing only about centralized
> workflow in this description, the above is a good write up.  Here is
> my version, including the push one:
>
>     It is the default for `git fetch` (hence `git pull`) and `git
>     push` when no arguments are given, and you are using the
>     centralized workflow.  To use a triangular workflow, in which
>     you fetch/pull from your upstream but you push your work to a
>     third repository, `git push` can be configured to push to
>     somewhere other than your upstream remote branch.

It makes sense to be more specific about `git push`. I like the idea of pointing out that you can use `pushremote` to make `git push` push to a different location.

I'm not comfortable with calling this a "triangular workflow" since there are other very popular ways to set up a sort of "triangular" workflow -- for example you can pull from one repo on the "main" branch and push to your personal repo on a feature branch. In that case each individual branch is set up in a "centralized" way but the overall workflow is "triangular". But it should be easy to talk about this without using the term "triangular workflow".

>     Various commands, including `git status`, `git checkout`, and
>     `git branch -v`, reminds you how many commits you have on top of
>     your upstream, and how many commits they added to your upstream
>     since your branch has forked from it.
This is great, will incorporate.
Show 32 quoted lines
> When we would upgrade this file with a more detailed description of
> the triangular workflow, we'd remove the "To use a triangular..."
> sentence from above, and leave it to the new section.
>
>> +The upstream is stored in `.git/config`, in the "remote" and "merge"
>> +fields. For example, if `main`'s upstream is `origin/main`:
>> +
>> +```
>> +[branch "main"]
>> +   remote = origin
>> +   merge = refs/heads/main
>> +```
>> +
>> +You can set an upstream branch explicitly with
>> +`git push --set-upstream <remote> <branch>` or `git branch --track`,
>> +but Git will often automatically set the upstream for you, for example:
>> +
>> +* When you clone a repository, Git will automatically set the upstream
>> +  for the default branch.
>> +* If you have the `push.autoSetupRemote` configuration option set,
>> +  `git push` will automatically set the upstream the first time you push
>> +  a branch.
>> +* Checking out a remote-tracking branch with `git checkout <branch>`
>> +  will automatically create a local branch with that name and set
>> +  the upstream to the remote branch.
>> +
>> +[NOTE]
>> +Upstream branches are sometimes referred to as "tracking information",
>> +as in "set the branch's tracking information".
>
> Everything you wrote here looks like a great addition.
> Nicely done.
Great to hear! :)
Junio C Hamano· Sep 15, 2025, 21:48 UTC · re: Julia Evans · lore

Re: [PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

"Julia Evans" <julia@jvns.ca> writes:
> I'm not comfortable with calling this a "triangular workflow" since

But it has been for a long time known as a "triangular workflow" already, so it is not like you are in your documentation update inventing the terminology. You do not have to feel unconfortable.

And this "each developer may internally use many branches, but at the public meeting points they share small number of branches (or just one) that integrate their work" is the most basic form of triangular workflow.

If you want to exclude all the advanced forms, without specifically singling out the triangular workflow, you can say "if you are not using the centralized workflow, and pushing to somewhere other than where you are fetching from, then do this..." and it would work fine, I guess.

Julia Evans· Sep 15, 2025, 23:09 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Mon, Sep 15, 2025, at 5:48 PM, Junio C Hamano wrote:
Show 7 quoted lines
> "Julia Evans" <julia@jvns.ca> writes:
>
>> I'm not comfortable with calling this a "triangular workflow" since
>
> But it has been for a long time known as a "triangular workflow"
> already, so it is not like you are in your documentation update
> inventing the terminology.  You do not have to feel unconfortable.

I'm not sure what you mean by that: according to `git grep` the term "triangular" is used only once in the Git documentation, somewhere in the middle of the `gitrevisions` man page. There are also a couple of mentions in the release notes.

It seems like the term "triangular workflow" has been used quite a bit on this mailing list but it's important to differentiate between terms that are commonly used internally in the Git developer community and terms which are actually used in the Git documentation and understood by users.

Show 10 quoted lines
> And this "each developer may internally use many branches, but at
> the public meeting points they share small number of branches (or
> just one) that integrate their work" is the most basic form of
> triangular workflow.
>
> If you want to exclude all the advanced forms, without specifically
> singling out the triangular workflow, you can say "if you are not
> using the centralized workflow, and pushing to somewhere other than
> where you are fetching from, then do this..." and it would work
> fine, I guess.
Junio C Hamano· Sep 16, 2025, 05:25 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 17 quoted lines
> diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes-upstreams.adoc
> similarity index 63%
> rename from Documentation/urls-remotes.adoc
> rename to Documentation/urls-remotes-upstreams.adoc
> index 9b10151198..1e9c56dc5f 100644
> --- a/Documentation/urls-remotes.adoc
> +++ b/Documentation/urls-remotes-upstreams.adoc
> @@ -91,6 +91,41 @@ git push uses:
> ...
> +The upstream is stored in `.git/config`, in the "remote" and "merge"
> +fields. For example, if `main`'s upstream is `origin/main`:
> +
> +```
> +[branch "main"]
> +   remote = origin
> +   merge = refs/heads/main
> +```
When running with AsciiDoc, this makes the build fail with
        ASCIIDOC git-fetch.html
    asciidoc: ERROR: urls-remotes-upstreams.adoc: line 111: illegal style name: branch "main"
    gmake: *** [Makefile:356: git-fetch.html] Error 1
The line #111 is the one that has [branch "main"] on it.

Curiously, USE_ASCIIDOCTOR=YesPlease would not suffer from the issue.

cf. https://github.com/git/git/actions/runs/17743739238/job/50423820029#step:4:1395
Junio C Hamano· Sep 16, 2025, 05:33 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

Junio C Hamano <gitster@pobox.com> writes:
Show 18 quoted lines
>> +```
>> +[branch "main"]
>> +   remote = origin
>> +   merge = refs/heads/main
>> +```
>
> When running with AsciiDoc, this makes the build fail with
>
>         ASCIIDOC git-fetch.html
>     asciidoc: ERROR: urls-remotes-upstreams.adoc: line 111: illegal style name: branch "main"
>     gmake: *** [Makefile:356: git-fetch.html] Error 1
>
> The line #111 is the one that has [branch "main"] on it.
>
> Curiously, USE_ASCIIDOCTOR=YesPlease would not suffer from the
> issue.
>
> cf. https://github.com/git/git/actions/runs/17743739238/job/50423820029#step:4:1395

For now I'd locally patch it with the attached, which does not seem to change the output at all when formatted with Asciidoctor, and does not break the build when AsciiDoctor is used.

Thanks.
Show changes to Documentation/urls-remotes-upstreams.adoc +3 −5
diff --git a/Documentation/urls-remotes-upstreams.adoc b/Documentation/urls-remotes-upstreams.adoc
index 1e9c56dc5f..f40db15b20 100644
--- a/Documentation/urls-remotes-upstreams.adoc
+++ b/Documentation/urls-remotes-upstreams.adoc
@@ -107,11 +107,9 @@ Git defaults to using the upstream branch for remote operations, for example:
 The upstream is stored in `.git/config`, in the "remote" and "merge"
 fields. For example, if `main`'s upstream is `origin/main`:
 
-```
-[branch "main"]
-   remote = origin
-   merge = refs/heads/main
-```
+	[branch "main"]
+	   remote = origin
+	   merge = refs/heads/main
 
 You can set an upstream branch explicitly with
 `git push --set-upstream <remote> <branch>` or `git branch --track`,
Junio C Hamano· Sep 16, 2025, 05:39 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

Junio C Hamano <gitster@pobox.com> writes:
> For now I'd locally patch it with the attached, which does not seem
> to change the output at all when formatted with Asciidoctor, and
> does not break the build when AsciiDoctor is used.

Sorry for the subtle typo on the last line. i.e. "AsciiDoctor" -> "AsciiDoc".

What I meant was that Asciidoctor has no issues with your version (while AsciiDoc complains), and with the attached patch, Asciidoctor produces identical output as your original, and AsciiDoc no longer complains.

Show 21 quoted lines
> Thanks.
>
> diff --git a/Documentation/urls-remotes-upstreams.adoc b/Documentation/urls-remotes-upstreams.adoc
> index 1e9c56dc5f..f40db15b20 100644
> --- a/Documentation/urls-remotes-upstreams.adoc
> +++ b/Documentation/urls-remotes-upstreams.adoc
> @@ -107,11 +107,9 @@ Git defaults to using the upstream branch for remote operations, for example:
>  The upstream is stored in `.git/config`, in the "remote" and "merge"
>  fields. For example, if `main`'s upstream is `origin/main`:
>  
> -```
> -[branch "main"]
> -   remote = origin
> -   merge = refs/heads/main
> -```
> +	[branch "main"]
> +	   remote = origin
> +	   merge = refs/heads/main
>  
>  You can set an upstream branch explicitly with
>  `git push --set-upstream <remote> <branch>` or `git branch --track`,
Julia Evans· Sep 18, 2025, 21:02 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Tue, Sep 16, 2025, at 1:39 AM, Junio C Hamano wrote:
Show 35 quoted lines
> Junio C Hamano <gitster@pobox.com> writes:
>
>> For now I'd locally patch it with the attached, which does not seem
>> to change the output at all when formatted with Asciidoctor, and
>> does not break the build when AsciiDoctor is used.
>
> Sorry for the subtle typo on the last line.  i.e. "AsciiDoctor" ->
> "AsciiDoc".
>
> What I meant was that Asciidoctor has no issues with your
> version (while AsciiDoc complains), and with the attached patch,
> Asciidoctor produces identical output as your original, and AsciiDoc
> no longer complains.
>
>> Thanks.
>>
>> diff --git a/Documentation/urls-remotes-upstreams.adoc b/Documentation/urls-remotes-upstreams.adoc
>> index 1e9c56dc5f..f40db15b20 100644
>> --- a/Documentation/urls-remotes-upstreams.adoc
>> +++ b/Documentation/urls-remotes-upstreams.adoc
>> @@ -107,11 +107,9 @@ Git defaults to using the upstream branch for remote operations, for example:
>>  The upstream is stored in `.git/config`, in the "remote" and "merge"
>>  fields. For example, if `main`'s upstream is `origin/main`:
>>  
>> -```
>> -[branch "main"]
>> -   remote = origin
>> -   merge = refs/heads/main
>> -```
>> +	[branch "main"]
>> +	   remote = origin
>> +	   merge = refs/heads/main
>>  
>>  You can set an upstream branch explicitly with
>>  `git push --set-upstream <remote> <branch>` or `git branch --track`,
Thanks for the patch, will fix.
Julia Evans via GitGitGadget· Sep 12, 2025, 18:55 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v2 3/4] doc: git-push: clarify "where to push"

From: Julia Evans <julia@jvns.ca>

Be clearer about what we're describing ("which repository" instead of "what to push"), and start with a positive "try X, then Y, then Z" instead of a negative ("if X is not specified..").

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
Show changes to Documentation/git-push.adoc +4 −4
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index ec396b4cf2..909c69766c 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -22,10 +22,10 @@ DESCRIPTION
 Updates one or more branches, tags, or other references in a remote
 repository from your local repository.
 
-When the command line does not specify where to push with the
-`<repository>` argument, `branch.*.remote` configuration for the
-current branch is consulted to determine where to push.  If the
-configuration is missing, it defaults to 'origin'.
+To decide which repository to push to, Git uses the `<repository>`
+argument (for example `git push dev`), then if that's not specified the
+upstream configuration for the current branch, and then defaults
+to `origin`.
 
 When the command line does not specify what to push with `<refspec>...`
 arguments or `--all`, `--mirror`, `--tags` options, the command finds
-- 
gitgitgadget
Junio C Hamano· Sep 12, 2025, 21:18 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v2 3/4] doc: git-push: clarify "where to push"

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 8 quoted lines
> -When the command line does not specify where to push with the
> -`<repository>` argument, `branch.*.remote` configuration for the
> -current branch is consulted to determine where to push.  If the
> -configuration is missing, it defaults to 'origin'.
> +To decide which repository to push to, Git uses the `<repository>`
> +argument (for example `git push dev`), then if that's not specified the
> +upstream configuration for the current branch, and then defaults
> +to `origin`.
OK.  Much less awkward and much clearer.  Nice.
Junio C Hamano· Sep 12, 2025, 21:19 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v2 3/4] doc: git-push: clarify "where to push"

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
> From: Julia Evans <julia@jvns.ca>
>
> Be clearer about what we're describing ("which repository" instead of
> "what to push"), and start with a positive "try X, then Y, then Z"
I forgot to say, even though I did spot:
    "what to push" -> "where to push"
"what to push" is the topic of the next patch.
Julia Evans· Sep 15, 2025, 20:52 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 3/4] doc: git-push: clarify "where to push"

Show 8 quoted lines
>> Be clearer about what we're describing ("which repository" instead of
>> "what to push"), and start with a positive "try X, then Y, then Z"
>
> I forgot to say, even though I did spot:
>
>     "what to push" -> "where to push"
>
> "what to push" is the topic of the next patch.
Thanks for spotting that. Will fix.
Julia Evans via GitGitGadget· Sep 12, 2025, 18:55 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v2 4/4] doc: git-push: clarify "what to push"

From: Julia Evans <julia@jvns.ca>

From user feedback: 6 users says they found the "what to push" paragraphs confusing, for many different reasons, including:

* what does "..." in <refspec>... mean?
* "consult XXX configuration" is hard to parse
* it refers to the `git-config` man page even though the config
  information for `git push` is included in this man page under
  CONFIGURATION
* the default ("push to a branch with the same name") is what they use
  99% of the time, they would have expected it to appear earlier instead
  of at the very end
* not understanding what the term "upstream" means in Git
  ("are branches tracked by some system besides their names?"")

Address all of these by using a numbered "in order of precedence" list (similar to the previous commit), by giving a little bit of context around "upstream branch": it's something that you may have to set explicitly, and referring to the new UPSTREAM BRANCHES section.

The default behaviour is still discussed pretty late but it should be easier to skim now to get to the relevant information.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)
Show changes to Documentation/git-push.adoc +14 −12
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index 909c69766c..2b2f753db4 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -27,18 +27,20 @@ argument (for example `git push dev`), then if that's not specified the
 upstream configuration for the current branch, and then defaults
 to `origin`.
 
-When the command line does not specify what to push with `<refspec>...`
-arguments or `--all`, `--mirror`, `--tags` options, the command finds
-the default `<refspec>` by consulting `remote.*.push` configuration,
-and if it is not found, honors `push.default` configuration to decide
-what to push (See linkgit:git-config[1] for the meaning of `push.default`).
-
-When neither the command-line nor the configuration specifies what to
-push, the default behavior is used, which corresponds to the `simple`
-value for `push.default`: the current branch is pushed to the
-corresponding upstream branch, but as a safety measure, the push is
-aborted if the upstream branch does not have the same name as the
-local one.
+To decide which branches, tags, or other refs to push, Git uses
+(in order of precedence):
+
+1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
+   or the `--all`, `--mirror`, or `--tags` options
+2. The `remote.*.push` configuration for the repository being pushed to
+3. The `push.default` configuration. The default is `push.default=simple`,
+   which will push to a branch with the same name as the current branch.
+   See the CONFIGURATION section below for more on `push.default`.
+
+As a safety measure, `git push` may fail if you haven't set an upstream
+for the current branch, depending on what `push.default` is set to.
+See the UPSTREAM BRANCHES section below for more on how to set and
+use upstreams.
 
 You can make interesting things happen to a repository
 every time you push into it, by setting up 'hooks' there.  See
-- 
gitgitgadget
Julia Evans via GitGitGadget· Sep 23, 2025, 17:44 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v3 0/4] doc: git-push: clarify DESCRIPTION section

I surveyed 16 Git users about the git push man page. Here's a rewrite of the DESCRIPTION section and the definition of <refspec> based on the feedback. The goal is to clarify it while communicating the same information. The most common piece of feedback was that folks didn't understand what the term "ref" means. Most of the users who said they did not understand the term "ref" have been using Git for 10+ years.

changes in v2:
 * The biggest change is to add a new UPSTREAM BRANCHES section to explain
   what an upstream is
 * Drop the "refspec" changes from this patch series, I've made revisions to
   them based on the comments here but I felt like this was getting too big.
 * Added some backticks `` that I'd missed, from Ben's review
 * From Junio's review, "The current branch must have a configured upstream
   with the same name, so this will fail when pushing a new branch" was not
   true, so replace it with a less detailed but hopefully true statement.
   After a very long conversation with Ben I realized that actually
   push.default=simple's behaviour is not really that simple (perhaps I
   should think of it as more "safe" than "simple", since "current" seems
   simpler), so it's more realistic to refer any questions to the
   CONFIGURATION section which describes the behaviour in more detail.
 * Rewrite all the commits to explain the problem they're trying to solve &
   thinking behind them in more detail. Let me know if I added too much /
   not enough detail.
changes in v3:
 * mention that git push also needs to send data in addition to updating the
   branch, from Junio's review
 * fix a newline, from Junio's review
 * un-rename urls-remotes.adoc, from Junio's review
 * mention pushRemote and git checkout in the UPSTREAM BRANCHES section and
   be clearer about what's meant by "the relationship between the current
   branch and the upstream", from Junio's review
 * fix AsciiDoc formatting issue, from Junio's review
Julia Evans (4):
  doc: git-push: clarify intro
  doc: add an UPSTREAM BRANCHES section to pull/push/fetch
  doc: git-push: clarify "where to push"
  doc: git-push: clarify "what to push"
 Documentation/git-push.adoc     | 43 +++++++++++++++++---------------
 Documentation/urls-remotes.adoc | 44 ++++++++++++++++++++++++++++++---
 2 files changed, 64 insertions(+), 23 deletions(-)
base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1964%2Fjvns%2Fclarify-push-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1964/jvns/clarify-push-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/1964
Range-diff vs v2:
 1:  270edd2b00 ! 1:  2870c77e80 doc: git-push: clarify intro
     @@ Documentation/git-push.adoc: SYNOPSIS
      -every time you push into it, by setting up 'hooks' there.  See
      -documentation for linkgit:git-receive-pack[1].
      +Updates one or more branches, tags, or other references in a remote
     -+repository from your local repository.
     ++repository from your local repository, and sends all necessary data
     ++that isn't already on the remote.
       
       When the command line does not specify where to push with the
       `<repository>` argument, `branch.*.remote` configuration for the
     @@ Documentation/git-push.adoc: corresponding upstream branch, but as a safety meas
      +You can make interesting things happen to a repository
      +every time you push into it, by setting up 'hooks' there.  See
      +documentation for linkgit:git-receive-pack[1].
     ++
       
       OPTIONS[[OPTIONS]]
       ------------------
 2:  0ec629d403 ! 2:  3ecfb5c3a6 doc: add an UPSTREAM BRANCHES section to pull/push/fetch
     @@ Commit message
      
          Signed-off-by: Julia Evans <julia@jvns.ca>
      
     - ## Documentation/git-fetch.adoc ##
     -@@ Documentation/git-fetch.adoc: include::pull-fetch-param.adoc[]
     - 	Read refspecs, one per line, from stdin in addition to those provided
     - 	as arguments. The "tag <name>" format is not supported.
     - 
     --include::urls-remotes.adoc[]
     -+include::urls-remotes-upstreams.adoc[]
     - 
     - 
     - CONFIGURED REMOTE-TRACKING BRANCHES[[CRTB]]
     -
     - ## Documentation/git-pull.adoc ##
     -@@ Documentation/git-pull.adoc: include::fetch-options.adoc[]
     - 
     - include::pull-fetch-param.adoc[]
     - 
     --include::urls-remotes.adoc[]
     -+include::urls-remotes-upstreams.adoc[]
     - 
     - include::merge-strategies.adoc[]
     - 
     -
     - ## Documentation/git-push.adoc ##
     -@@ Documentation/git-push.adoc: further recursion will occur. In this case, "only" is treated as "on-demand".
     - --ipv6::
     - 	Use IPv6 addresses only, ignoring IPv4 addresses.
     - 
     --include::urls-remotes.adoc[]
     -+include::urls-remotes-upstreams.adoc[]
     - 
     - OUTPUT
     - ------
     -
     - ## Documentation/urls-remotes.adoc => Documentation/urls-remotes-upstreams.adoc ##
     -@@ Documentation/urls-remotes-upstreams.adoc: git push uses:
     + ## Documentation/urls-remotes.adoc ##
     +@@ Documentation/urls-remotes.adoc: git push uses:
       	HEAD:refs/heads/<head>
       ------------
       
     @@ Documentation/urls-remotes-upstreams.adoc: git push uses:
      +Git defaults to using the upstream branch for remote operations, for example:
      +
      +* It's the default for `git pull` or `git fetch` with no arguments
     -+* It's sometimes the default for `git push` with no arguments. See the
     -+  `push.default` section of linkgit:git-config[1] for the details.
     -+* `git status` and `git branch -v` will show the
     -+  relationship between the current branch and the upstream,
     -+  for example "Your branch is up to date with origin/main"
     ++* It's the default for `git push` with no arguments, with some exceptions.
     ++  For example, you can use the `branch.<name>.pushRemote` option to push
     ++  to a different remote than you pull from, and by default with
     ++  `push.default=simple` the upstream branch you configure must have
     ++  the same name.
     ++* Various commands, including `git checkout` and `git status`, will
     ++  show you how many commits have been added to your current branch and
     ++  the upstream since you forked from it, for example "Your branch and
     ++  'origin/main' have diverged, and have 2 and 3 different commits each
     ++  respectively"
      +
      +The upstream is stored in `.git/config`, in the "remote" and "merge"
      +fields. For example, if `main`'s upstream is `origin/main`:
      +
     -+```
     -+[branch "main"]
     -+   remote = origin
     -+   merge = refs/heads/main
     -+```
     ++	[branch "main"]
     ++	   remote = origin
     ++	   merge = refs/heads/main
      +
      +You can set an upstream branch explicitly with
      +`git push --set-upstream <remote> <branch>` or `git branch --track`,
 3:  374740c678 ! 3:  bfd6072983 doc: git-push: clarify "where to push"
     @@ Commit message
          doc: git-push: clarify "where to push"
      
          Be clearer about what we're describing ("which repository" instead of
     -    "what to push"), and start with a positive "try X, then Y, then Z"
     +    "where to push"), and start with a positive "try X, then Y, then Z"
          instead of a negative ("if X is not specified..").
      
          Signed-off-by: Julia Evans <julia@jvns.ca>
      
       ## Documentation/git-push.adoc ##
     -@@ Documentation/git-push.adoc: DESCRIPTION
     - Updates one or more branches, tags, or other references in a remote
     - repository from your local repository.
     +@@ Documentation/git-push.adoc: Updates one or more branches, tags, or other references in a remote
     + repository from your local repository, and sends all necessary data
     + that isn't already on the remote.
       
      -When the command line does not specify where to push with the
      -`<repository>` argument, `branch.*.remote` configuration for the
 4:  59732f1e47 = 4:  be6453d010 doc: git-push: clarify "what to push"
-- 
gitgitgadget
Julia Evans via GitGitGadget· Sep 23, 2025, 17:44 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v3 1/4] doc: git-push: clarify intro

From: Julia Evans <julia@jvns.ca>

From user feedback, 5 users are unsure what "ref" and/or "objects" means in this context. 3 users said they don't know what "complete the refs" means.

Many users also commented that receive hooks do not seem like the most important thing to know about `git push`, and that this information should not be the second sentence in the man page.

Use more familiar language to make it more accessible to users who do not know what a "ref" is and move the "hooks" comment to the end.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
Show changes to Documentation/git-push.adoc +7 −6
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index d1978650d6..25d972f248 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -19,12 +19,9 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Updates remote refs using local refs, while sending objects
-necessary to complete the given refs.
-
-You can make interesting things happen to a repository
-every time you push into it, by setting up 'hooks' there.  See
-documentation for linkgit:git-receive-pack[1].
+Updates one or more branches, tags, or other references in a remote
+repository from your local repository, and sends all necessary data
+that isn't already on the remote.
 
 When the command line does not specify where to push with the
 `<repository>` argument, `branch.*.remote` configuration for the
@@ -44,6 +41,10 @@ corresponding upstream branch, but as a safety measure, the push is
 aborted if the upstream branch does not have the same name as the
 local one.
 
+You can make interesting things happen to a repository
+every time you push into it, by setting up 'hooks' there.  See
+documentation for linkgit:git-receive-pack[1].
+
 
 OPTIONS[[OPTIONS]]
 ------------------
-- 
gitgitgadget
Julia Evans via GitGitGadget· Sep 23, 2025, 17:44 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v3 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

From: Julia Evans <julia@jvns.ca>

From user feedback: one user mentioned that they don't know what the term "upstream branch" means. As far as I can tell, the most complete description is under the `--track` option in `git branch`. Upstreams are an important concept in Git and the `git branch` man page is not an obvious place for that information to live.

There's also a very terse description of "upstream branch" in the glossary that's missing a lot of key information, like the fact that the upstream is used by `git status` and `git pull`, as well as a description in `git-config` in `branch.<name>.remote` which doesn't explain the relationship to `git status` either.

Since the `git pull`, `git push`, and `git fetch` man pages already include sections on REMOTES and the syntax for URLs, add a section on UPSTREAM BRANCHES to `urls-remotes.adoc` and rename it to `urls-remotes-upstreams.adoc`. That's an awkward name but at least it's clear what's in the file.

In the new UPSTREAM BRANCHES section, cover the various ways that upstreams branches are automatically set in Git, since users may mistakenly think that their branch does not have an upstream branch if they didn't explicitly set one.

A terminology note: Git uses two terms for this concept:
- "tracking" as in "the current branch is _tracking_ some remote"
  or the `--track` option to `git branch`
- "upstream" or "upstream branch", as in `git push --set-upstream`.
  This term is also used in the `git rebase` man page to refer to the
  first argument to `git rebase`, as well as in `git pull` to refer to
  the branch which is going to be merged into the current branch ("merge
  the upstream branch into the current branch")

Use "upstream branch" as a heading for this concept even though the term "upstream branch" is not always used strictly in the sense of "the tracking information for the current branch". "Upstream" is used much more often than "tracking" in the Git docs to refer to this concept and the goal is to help users understand the docs.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/urls-remotes.adoc | 44 ++++++++++++++++++++++++++++++---
 1 file changed, 41 insertions(+), 3 deletions(-)
Show changes to Documentation/urls-remotes.adoc +41 −3
diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes.adoc
index 9b10151198..1138a5889d 100644
--- a/Documentation/urls-remotes.adoc
+++ b/Documentation/urls-remotes.adoc
@@ -91,6 +91,44 @@ git push uses:
 	HEAD:refs/heads/<head>
 ------------
 
-
-
-
+UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
+--------------------------------------
+
+Branches in Git can optionally have an upstream remote branch.
+Git defaults to using the upstream branch for remote operations, for example:
+
+* It's the default for `git pull` or `git fetch` with no arguments
+* It's the default for `git push` with no arguments, with some exceptions.
+  For example, you can use the `branch.<name>.pushRemote` option to push
+  to a different remote than you pull from, and by default with
+  `push.default=simple` the upstream branch you configure must have
+  the same name.
+* Various commands, including `git checkout` and `git status`, will
+  show you how many commits have been added to your current branch and
+  the upstream since you forked from it, for example "Your branch and
+  'origin/main' have diverged, and have 2 and 3 different commits each
+  respectively"
+
+The upstream is stored in `.git/config`, in the "remote" and "merge"
+fields. For example, if `main`'s upstream is `origin/main`:
+
+	[branch "main"]
+	   remote = origin
+	   merge = refs/heads/main
+
+You can set an upstream branch explicitly with
+`git push --set-upstream <remote> <branch>` or `git branch --track`,
+but Git will often automatically set the upstream for you, for example:
+
+* When you clone a repository, Git will automatically set the upstream
+  for the default branch.
+* If you have the `push.autoSetupRemote` configuration option set,
+  `git push` will automatically set the upstream the first time you push
+  a branch.
+* Checking out a remote-tracking branch with `git checkout <branch>`
+  will automatically create a local branch with that name and set
+  the upstream to the remote branch.
+
+[NOTE]
+Upstream branches are sometimes referred to as "tracking information",
+as in "set the branch's tracking information".
-- 
gitgitgadget
Junio C Hamano· Sep 24, 2025, 19:51 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v3 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 5 quoted lines
> Since the `git pull`, `git push`, and `git fetch` man pages already
> include sections on REMOTES and the syntax for URLs, add a section on
> UPSTREAM BRANCHES to `urls-remotes.adoc` and rename it to
> `urls-remotes-upstreams.adoc`. That's an awkward name but at least it's
> clear what's in the file.

You no longer do any such thing ;-) I can locally everyting after "and rename it ..." and replace it with a single full-stop "." so unless there are other things you would need to update this topic with, no need to correct only this part.

Show 9 quoted lines
> In the new UPSTREAM BRANCHES section, cover the various ways that
> upstreams branches are automatically set in Git, since users may
> mistakenly think that their branch does not have an upstream branch if
> they didn't explicitly set one.
>
> A terminology note: Git uses two terms for this concept:
>
> - "tracking" as in "the current branch is _tracking_ some remote"
>   or the `--track` option to `git branch`

Should we say "tracking some branch at a remote"? It is not like the current branch tracks more than one (or all) branches at the remote as a whole.

Show 5 quoted lines
> - "upstream" or "upstream branch", as in `git push --set-upstream`.
>   This term is also used in the `git rebase` man page to refer to the
>   first argument to `git rebase`, as well as in `git pull` to refer to
>   the branch which is going to be merged into the current branch ("merge
>   the upstream branch into the current branch")
This side is fine.
Show 5 quoted lines
> Use "upstream branch" as a heading for this concept even though the term
> "upstream branch" is not always used strictly in the sense of "the
> tracking information for the current branch". "Upstream" is used much
> more often than "tracking" in the Git docs to refer to this concept and
> the goal is to help users understand the docs.
Good.
Show 13 quoted lines
> diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes.adoc
> index 9b10151198..1138a5889d 100644
> --- a/Documentation/urls-remotes.adoc
> +++ b/Documentation/urls-remotes.adoc
> @@ -91,6 +91,44 @@ git push uses:
>  	HEAD:refs/heads/<head>
>  ------------
>  
> -
> -
> -
> +UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
> +--------------------------------------

Can we have at least two blank lines between these sections to make it visually distinct from a gap between two paragraphs? I know it would not make a difference in the rendered pages, but it would help those who read the document in the source form.

Show 5 quoted lines
> +
> +Branches in Git can optionally have an upstream remote branch.
> +Git defaults to using the upstream branch for remote operations, for example:
> +
> +* It's the default for `git pull` or `git fetch` with no arguments

I think you'd want to finish this sentence with a full-stop ".", and a few lines below, the point beginning with "Various commands".

Show 10 quoted lines
> +* It's the default for `git push` with no arguments, with some exceptions.
> +  For example, you can use the `branch.<name>.pushRemote` option to push
> +  to a different remote than you pull from, and by default with
> +  `push.default=simple` the upstream branch you configure must have
> +  the same name.
> +* Various commands, including `git checkout` and `git status`, will
> +  show you how many commits have been added to your current branch and
> +  the upstream since you forked from it, for example "Your branch and
> +  'origin/main' have diverged, and have 2 and 3 different commits each
> +  respectively"

Other than these, all changes from the previous version look good to me.

Thanks.
Julia Evans· Sep 30, 2025, 19:20 UTC · re: Junio C Hamano · lore

Re: [PATCH v3 2/4] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Wed, Sep 24, 2025, at 3:51 PM, Junio C Hamano wrote:
Show 12 quoted lines
> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
>> Since the `git pull`, `git push`, and `git fetch` man pages already
>> include sections on REMOTES and the syntax for URLs, add a section on
>> UPSTREAM BRANCHES to `urls-remotes.adoc` and rename it to
>> `urls-remotes-upstreams.adoc`. That's an awkward name but at least it's
>> clear what's in the file.
>
> You no longer do any such thing ;-) I can locally everyting after
> "and rename it ..." and replace it with a single full-stop "." so
> unless there are other things you would need to update this topic
> with, no need to correct only this part.
Will fix this (and everything else you mentioned in this email), thanks.
Show 73 quoted lines
>> In the new UPSTREAM BRANCHES section, cover the various ways that
>> upstreams branches are automatically set in Git, since users may
>> mistakenly think that their branch does not have an upstream branch if
>> they didn't explicitly set one.
>>
>> A terminology note: Git uses two terms for this concept:
>>
>> - "tracking" as in "the current branch is _tracking_ some remote"
>>   or the `--track` option to `git branch`
>
> Should we say "tracking some branch at a remote"?  It is not like
> the current branch tracks more than one (or all) branches at the
> remote as a whole.
>
>> - "upstream" or "upstream branch", as in `git push --set-upstream`.
>>   This term is also used in the `git rebase` man page to refer to the
>>   first argument to `git rebase`, as well as in `git pull` to refer to
>>   the branch which is going to be merged into the current branch ("merge
>>   the upstream branch into the current branch")
>
> This side is fine.
>
>> Use "upstream branch" as a heading for this concept even though the term
>> "upstream branch" is not always used strictly in the sense of "the
>> tracking information for the current branch". "Upstream" is used much
>> more often than "tracking" in the Git docs to refer to this concept and
>> the goal is to help users understand the docs.
>
> Good.
>
>> diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes.adoc
>> index 9b10151198..1138a5889d 100644
>> --- a/Documentation/urls-remotes.adoc
>> +++ b/Documentation/urls-remotes.adoc
>> @@ -91,6 +91,44 @@ git push uses:
>>  	HEAD:refs/heads/<head>
>>  ------------
>>  
>> -
>> -
>> -
>> +UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
>> +--------------------------------------
>
> Can we have at least two blank lines between these sections to make
> it visually distinct from a gap between two paragraphs?  I know it
> would not make a difference in the rendered pages, but it would help
> those who read the document in the source form.
>
>> +
>> +Branches in Git can optionally have an upstream remote branch.
>> +Git defaults to using the upstream branch for remote operations, for example:
>> +
>> +* It's the default for `git pull` or `git fetch` with no arguments
>
> I think you'd want to finish this sentence with a full-stop ".", and
> a few lines below, the point beginning with "Various commands".
>
>> +* It's the default for `git push` with no arguments, with some exceptions.
>> +  For example, you can use the `branch.<name>.pushRemote` option to push
>> +  to a different remote than you pull from, and by default with
>> +  `push.default=simple` the upstream branch you configure must have
>> +  the same name.
>> +* Various commands, including `git checkout` and `git status`, will
>> +  show you how many commits have been added to your current branch and
>> +  the upstream since you forked from it, for example "Your branch and
>> +  'origin/main' have diverged, and have 2 and 3 different commits each
>> +  respectively"
>
> Other than these, all changes from the previous version look good to
> me.
>
> Thanks.
Julia Evans via GitGitGadget· Sep 23, 2025, 17:44 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v3 3/4] doc: git-push: clarify "where to push"

From: Julia Evans <julia@jvns.ca>

Be clearer about what we're describing ("which repository" instead of "where to push"), and start with a positive "try X, then Y, then Z" instead of a negative ("if X is not specified..").

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
Show changes to Documentation/git-push.adoc +4 −4
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index 25d972f248..368f2625a2 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -23,10 +23,10 @@ Updates one or more branches, tags, or other references in a remote
 repository from your local repository, and sends all necessary data
 that isn't already on the remote.
 
-When the command line does not specify where to push with the
-`<repository>` argument, `branch.*.remote` configuration for the
-current branch is consulted to determine where to push.  If the
-configuration is missing, it defaults to 'origin'.
+To decide which repository to push to, Git uses the `<repository>`
+argument (for example `git push dev`), then if that's not specified the
+upstream configuration for the current branch, and then defaults
+to `origin`.
 
 When the command line does not specify what to push with `<refspec>...`
 arguments or `--all`, `--mirror`, `--tags` options, the command finds
-- 
gitgitgadget
Julia Evans via GitGitGadget· Sep 23, 2025, 17:44 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v3 4/4] doc: git-push: clarify "what to push"

From: Julia Evans <julia@jvns.ca>

From user feedback: 6 users says they found the "what to push" paragraphs confusing, for many different reasons, including:

* what does "..." in <refspec>... mean?
* "consult XXX configuration" is hard to parse
* it refers to the `git-config` man page even though the config
  information for `git push` is included in this man page under
  CONFIGURATION
* the default ("push to a branch with the same name") is what they use
  99% of the time, they would have expected it to appear earlier instead
  of at the very end
* not understanding what the term "upstream" means in Git
  ("are branches tracked by some system besides their names?"")

Address all of these by using a numbered "in order of precedence" list (similar to the previous commit), by giving a little bit of context around "upstream branch": it's something that you may have to set explicitly, and referring to the new UPSTREAM BRANCHES section.

The default behaviour is still discussed pretty late but it should be easier to skim now to get to the relevant information.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)
Show changes to Documentation/git-push.adoc +14 −12
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index 368f2625a2..839e6abeec 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -28,18 +28,20 @@ argument (for example `git push dev`), then if that's not specified the
 upstream configuration for the current branch, and then defaults
 to `origin`.
 
-When the command line does not specify what to push with `<refspec>...`
-arguments or `--all`, `--mirror`, `--tags` options, the command finds
-the default `<refspec>` by consulting `remote.*.push` configuration,
-and if it is not found, honors `push.default` configuration to decide
-what to push (See linkgit:git-config[1] for the meaning of `push.default`).
-
-When neither the command-line nor the configuration specifies what to
-push, the default behavior is used, which corresponds to the `simple`
-value for `push.default`: the current branch is pushed to the
-corresponding upstream branch, but as a safety measure, the push is
-aborted if the upstream branch does not have the same name as the
-local one.
+To decide which branches, tags, or other refs to push, Git uses
+(in order of precedence):
+
+1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
+   or the `--all`, `--mirror`, or `--tags` options
+2. The `remote.*.push` configuration for the repository being pushed to
+3. The `push.default` configuration. The default is `push.default=simple`,
+   which will push to a branch with the same name as the current branch.
+   See the CONFIGURATION section below for more on `push.default`.
+
+As a safety measure, `git push` may fail if you haven't set an upstream
+for the current branch, depending on what `push.default` is set to.
+See the UPSTREAM BRANCHES section below for more on how to set and
+use upstreams.
 
 You can make interesting things happen to a repository
 every time you push into it, by setting up 'hooks' there.  See
-- 
gitgitgadget
Junio C Hamano· Sep 24, 2025, 20:01 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 12 quoted lines
> -When the command line does not specify what to push with `<refspec>...`
> -arguments or `--all`, `--mirror`, `--tags` options, the command finds
> -the default `<refspec>` by consulting `remote.*.push` configuration,
> -and if it is not found, honors `push.default` configuration to decide
> -what to push (See linkgit:git-config[1] for the meaning of `push.default`).
> -
> -When neither the command-line nor the configuration specifies what to
> -push, the default behavior is used, which corresponds to the `simple`
> -value for `push.default`: the current branch is pushed to the
> -corresponding upstream branch, but as a safety measure, the push is
> -aborted if the upstream branch does not have the same name as the
> -local one.
That's a lot of text, and ...
Show 9 quoted lines
> +To decide which branches, tags, or other refs to push, Git uses
> +(in order of precedence):
> +
> +1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
> +   or the `--all`, `--mirror`, or `--tags` options
> +2. The `remote.*.push` configuration for the repository being pushed to
> +3. The `push.default` configuration. The default is `push.default=simple`,
> +   which will push to a branch with the same name as the current branch.
> +   See the CONFIGURATION section below for more on `push.default`.

.. the above gives us vastly more pleasant readability improvement. Nice.

I do not know if you want to do anything to the lack of any punctuation at the end of sentences 1. and 2. (I would have written ';' if I were writing this myself).

> +As a safety measure, `git push` may fail if you haven't set an upstream
> +for the current branch, depending on what `push.default` is set to.
> +See the UPSTREAM BRANCHES section below for more on how to set and
> +use upstreams.
This feels a bit out of place, as the safety measure, as I
understand it, is only relevant in 3. and only when push.default is
set to "simple".  If we are referring the user to the configuration
section, then it may be a better place to say that the "simple"
setting requires you to integrate with the branch with the same name.
 
Thanks.
Julia Evans· Sep 25, 2025, 20:50 UTC · re: Junio C Hamano · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

On Wed, Sep 24, 2025, at 4:01 PM, Junio C Hamano wrote:
Show 44 quoted lines
> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
>> -When the command line does not specify what to push with `<refspec>...`
>> -arguments or `--all`, `--mirror`, `--tags` options, the command finds
>> -the default `<refspec>` by consulting `remote.*.push` configuration,
>> -and if it is not found, honors `push.default` configuration to decide
>> -what to push (See linkgit:git-config[1] for the meaning of `push.default`).
>> -
>> -When neither the command-line nor the configuration specifies what to
>> -push, the default behavior is used, which corresponds to the `simple`
>> -value for `push.default`: the current branch is pushed to the
>> -corresponding upstream branch, but as a safety measure, the push is
>> -aborted if the upstream branch does not have the same name as the
>> -local one.
>
> That's a lot of text, and ...
>
>> +To decide which branches, tags, or other refs to push, Git uses
>> +(in order of precedence):
>> +
>> +1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
>> +   or the `--all`, `--mirror`, or `--tags` options
>> +2. The `remote.*.push` configuration for the repository being pushed to
>> +3. The `push.default` configuration. The default is `push.default=simple`,
>> +   which will push to a branch with the same name as the current branch.
>> +   See the CONFIGURATION section below for more on `push.default`.
>
> .. the above gives us vastly more pleasant readability improvement.
> Nice.
>
> I do not know if you want to do anything to the lack of any
> punctuation at the end of sentences 1. and 2. (I would have written
> ';' if I were writing this myself).
>
>> +As a safety measure, `git push` may fail if you haven't set an upstream
>> +for the current branch, depending on what `push.default` is set to.
>> +See the UPSTREAM BRANCHES section below for more on how to set and
>> +use upstreams.
>
> This feels a bit out of place, as the safety measure, as I
> understand it, is only relevant in 3. and only when push.default is
> set to "simple".  If we are referring the user to the configuration
> section, then it may be a better place to say that the "simple"
> setting requires you to integrate with the branch with the same name.

That makes sense. My goal here is really to communicate that you may need to set an upstream for `git push` to work, since it hasn't been mentioned yet that the upstream branch might be involved in deciding what remote branch to push to, and it comes up pretty often when using the command. Perhaps this instead:

"Depending on the value of `push.default`, git push` may fail if the current branch doesn't have a configured upstream branch. See the UPSTREAM BRANCHES section below for more on how to set and use upstreams."

> Thanks.
Junio C Hamano· Sep 25, 2025, 21:15 UTC · re: Julia Evans · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

"Julia Evans" <julia@jvns.ca> writes:
Show 15 quoted lines
>>> +As a safety measure, `git push` may fail if you haven't set an upstream
>>> +for the current branch, depending on what `push.default` is set to.
>>> +See the UPSTREAM BRANCHES section below for more on how to set and
>>> +use upstreams.
>>
>> This feels a bit out of place, as the safety measure, as I
>> understand it, is only relevant in 3. and only when push.default is
>> set to "simple".  If we are referring the user to the configuration
>> section, then it may be a better place to say that the "simple"
>> setting requires you to integrate with the branch with the same name.
>
> That makes sense. My goal here is really to communicate that you may need
> to set an upstream for `git push` to work, since it hasn't been mentioned yet
> that the upstream branch might be involved in deciding what remote branch
> to push to, and it comes up pretty often when using the command.

Actually, I think it is a mistake to tell people to use unadorned "git push" all the time. Have them say "git push origin mytopic", get them feel sick of doing so all the time, and then tell them they do not have to if they set an upstream for the current branch. IOW, "sometimes you need to" is the source of the confusion that comes from giving them too much DWIMmery. You'd by default need to tell Git, because you know more about your project than Git does, until you tell Git once, after which Git knows what to do.

Show 6 quoted lines
> Perhaps this instead:
>
> "Depending on the value of `push.default`, git push` may fail if the current
> branch doesn't have a configured upstream branch.
> See the UPSTREAM BRANCHES section below for more on how to set and
> use upstreams."
So, rather, something like this
    "git push" needs to know what branch to push to update what
    branch of which repository.  It is done by giving command line
    arguments and/or setting configuration variables to the command.
    See UPSTREAM BRANCHES section for more information.

would be more in line with a preferrable mindset users would have to successfully use "git push", I think.

Julia Evans· Sep 25, 2025, 22:34 UTC · re: Junio C Hamano · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

On Thu, Sep 25, 2025, at 5:15 PM, Junio C Hamano wrote:
Show 43 quoted lines
> "Julia Evans" <julia@jvns.ca> writes:
>
>>>> +As a safety measure, `git push` may fail if you haven't set an upstream
>>>> +for the current branch, depending on what `push.default` is set to.
>>>> +See the UPSTREAM BRANCHES section below for more on how to set and
>>>> +use upstreams.
>>>
>>> This feels a bit out of place, as the safety measure, as I
>>> understand it, is only relevant in 3. and only when push.default is
>>> set to "simple".  If we are referring the user to the configuration
>>> section, then it may be a better place to say that the "simple"
>>> setting requires you to integrate with the branch with the same name.
>>
>> That makes sense. My goal here is really to communicate that you may need
>> to set an upstream for `git push` to work, since it hasn't been mentioned yet
>> that the upstream branch might be involved in deciding what remote branch
>> to push to, and it comes up pretty often when using the command.
>
> Actually, I think it is a mistake to tell people to use unadorned
> "git push" all the time.  Have them say "git push origin mytopic",
> get them feel sick of doing so all the time, and then tell them they
> do not have to if they set an upstream for the current branch.  IOW,
> "sometimes you need to" is the source of the confusion that comes
> from giving them too much DWIMmery.  You'd by default need to tell
> Git, because you know more about your project than Git does, until
> you tell Git once, after which Git knows what to do.
>
>> Perhaps this instead:
>>
>> "Depending on the value of `push.default`, git push` may fail if the current
>> branch doesn't have a configured upstream branch.
>> See the UPSTREAM BRANCHES section below for more on how to set and
>> use upstreams."
>
> So, rather, something like this
>
>     "git push" needs to know what branch to push to update what
>     branch of which repository.  It is done by giving command line
>     arguments and/or setting configuration variables to the command.
>     See UPSTREAM BRANCHES section for more information.
>
> would be more in line with a preferrable mindset users would have to
> successfully use "git push", I think.

In principle I like the idea of saying that "git push needs to know what branch to update...", it's a clear statement and it seems logical.

But I'm not sure it's true in this case: we just said above that "The default is `push.default=simple`, which will push to a branch with the same name as the current branch." So with push.default=simple, Git already knows what branch it will update, it's the branch with the same name.

As I understand it, with push.default=simple, the reason you need to set the upstream is not to tell Git what branch to update (since Git will not even let you set the upstream to a branch with a different name), but instead it's more of a safety check to prevent you from accidentally pushing a branch that you didn't mean to. Is that wrong?

Junio C Hamano· Sep 26, 2025, 01:27 UTC · re: Julia Evans · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

"Julia Evans" <julia@jvns.ca> writes:
Show 5 quoted lines
> As I understand it, with push.default=simple, the reason you need to set
> the upstream is not to tell Git what branch to update (since Git will not
> even let you set the upstream to a branch with a different name), but
> instead it's more of a safety check to prevent you from accidentally
> pushing a branch that you didn't mean to. Is that wrong?

Your understanding is correct, but when push.default=simple castrates "git push", and you are on branch 'foo', it is dubious to argue that "git push" _knows_ it will be pushed to 'foo' at origin.

It is very much conditional---what Git is being told is that the push would be made there only if branch.foo.{remote,merge} were set up to push these. If the setting is not there, then Git does not know where to push to.

I agree with you that setting these configurations is *not* about letting Git know. It is about lifting that conditional that prevents Git from knowing where to push to.

> But I'm not sure it's true in this case: we just said above that
> "The default is `push.default=simple`, which will push to a branch with
> the same name as the current branch."

So I think this simplified statement is what causes confusion. It says push.default=simple will push to such and such place, but that is not true. push.default=simple only means that no settings that points a branch with different name as your upstream is accepted. And configured upstream is what determines what branch at what remote is updated with a push.

You can tell the same story about push.default=upstream; configured upstream is what determines what branch at what remote is updated in this case, too, and it won't push out if you do not have your upstream configured.

Junio C Hamano· Sep 26, 2025, 15:29 UTC · re: Junio C Hamano · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

Junio C Hamano <gitster@pobox.com> writes:
Show 7 quoted lines
>> But I'm not sure it's true in this case: we just said above that
>> "The default is `push.default=simple`, which will push to a branch with
>> the same name as the current branch."
>
> So I think this simplified statement is what causes confusion.  It
> says push.default=simple will push to such and such place, but that
> is not true....

After sleeping on this, I do think that at the crux of confusing wording in the current draft is the lack of stress on "simple" being a narrower special case of more general "upstream" for various push.default modes. In either of these modes, unless told otherwise with the configuration file or the command line arguments, "git push" pushes to update the upstream of the current branch. There is, as you said, an additional safety measure in the "simple" mode, that rejects a configuration to have a branch whose name is different in the remote repository as the upstream branch.

In other words, the push.default=simple mode does not tell Git to push to a branch with the same name. Rather, as a variant of the push.default=upstream mode, it tells Git to follow the same "push to the upstream branch" rule, which requires you to configure your upstream. But the mode gives additional limit on the name of the branch that can be set to upstream.

We should make our text clear enough that anybody who read about the push.default=simple configuration easily understand the above. We would need to find a good division between what to put in the main text and what to leave out to the "see ... for more detauls" part to guide those who read about "git push" command to the same realization without bombarding them with descriptions of full range of possible values of push.default.

Peeking our earlier exchange to help me formulate my thinking a bit...

Show 14 quoted lines
> +To decide which branches, tags, or other refs to push, Git uses
> +(in order of precedence):
> +
> +1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
> +   or the `--all`, `--mirror`, or `--tags` options
> +2. The `remote.*.push` configuration for the repository being pushed to
> +3. The `push.default` configuration. The default is `push.default=simple`,
> +   which will push to a branch with the same name as the current branch.
> +   See the CONFIGURATION section below for more on `push.default`.
> +
> +As a safety measure, `git push` may fail if you haven't set an upstream
> +for the current branch, depending on what `push.default` is set to.
> +See the UPSTREAM BRANCHES section below for more on how to set and
> +use upstreams.
... here is my attempt.
    3. The `push.default` configuration. The default is `simple`,
       which is a variant of `upstream`.  In either mode, "git push"
       updates the configured upstream branch (see the UPSTREAM
       BRANCHES section for more on how to set and use upstreams).
       The 'simple' mode has an additional limitation that the name
       of your configured upstream must be the same as your branch.
(iow, I rolled the "As a safety measure" paragraph into 3. itself).
Julia Evans· Sep 26, 2025, 17:31 UTC · re: Junio C Hamano · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

On Fri, Sep 26, 2025, at 11:29 AM, Junio C Hamano wrote:
Show 26 quoted lines
> Junio C Hamano <gitster@pobox.com> writes:
>
>>> But I'm not sure it's true in this case: we just said above that
>>> "The default is `push.default=simple`, which will push to a branch with
>>> the same name as the current branch."
>>
>> So I think this simplified statement is what causes confusion.  It
>> says push.default=simple will push to such and such place, but that
>> is not true....
>
> After sleeping on this, I do think that at the crux of confusing
> wording in the current draft is the lack of stress on "simple" being
> a narrower special case of more general "upstream" for various
> push.default modes.  In either of these modes, unless told otherwise
> with the configuration file or the command line arguments, "git
> push" pushes to update the upstream of the current branch.  There
> is, as you said, an additional safety measure in the "simple" mode,
> that rejects a configuration to have a branch whose name is
> different in the remote repository as the upstream branch.
>
> In other words, the push.default=simple mode does not tell Git to
> push to a branch with the same name.  Rather, as a variant of the
> push.default=upstream mode, it tells Git to follow the same "push to
> the upstream branch" rule, which requires you to configure your
> upstream.  But the mode gives additional limit on the name of the
> branch that can be set to upstream.

I like the idea of explaining it as "push.default=simple uses the configured upstream branch, with the restriction that the upstream branch must have the same name".

But as I learned from you earlier in this thread: https://lore.kernel.org/git/pull.1964.v2.git.1757703309.gitgitgadget@gmail.com/T/#m896f4a32ca462d69637b56f9bdfaa61e55e6b952 push.default=simple will sometimes push the current branch to the remote branch with the same name even if there's no configured upstream branch.

So it seems more accurate to say that push.default.simple will push to the branch with the same name, with the restriction that you might have to set an upstream, because the branch must always have the same name, but whether or not you have to set an upstream depends on the situation.

Personally that behaviour seems unintuitive to me: I always thought that push.default=simple _did_ require you to set an upstream branch and after spending many hours thinking about I still can't really describe in a way that feels satisfactory to me why it sometimes doesn't and under what conditions that happens.

One idea I had was to change Git's behaviour so that push.default=simple _does_ require you to set an upstream branch, and then we could document that behaviour. That's how it used to work when push.default=simple was originally created and it's not clear to me if the change to make push.default=simple _not_ always require you to set an upstream was intentional or not. I did a git bisect to find out when this changed, and it was in https://github.com/git/git/commit/ed2b18292bfeedc98c9e2b6bd8a35d8001dab2fc commit ed2b18292bfeed

I tried to write a patch to require setting an upstream branch, though my commit message has some mistakes and I'm not at all sure of my understanding of the code. https://github.com/jvns/git/commit/3553479892b11c50de939707e7f00aa7c7cb2f9d

Show 36 quoted lines
> We should make our text clear enough that anybody who read about the
> push.default=simple configuration easily understand the above.  We
> would need to find a good division between what to put in the main
> text and what to leave out to the "see ... for more detauls" part to
> guide those who read about "git push" command to the same
> realization without bombarding them with descriptions of full range
> of possible values of push.default.
>
> Peeking our earlier exchange to help me formulate my thinking a
> bit...
>
>> +To decide which branches, tags, or other refs to push, Git uses
>> +(in order of precedence):
>> +
>> +1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
>> +   or the `--all`, `--mirror`, or `--tags` options
>> +2. The `remote.*.push` configuration for the repository being pushed to
>> +3. The `push.default` configuration. The default is `push.default=simple`,
>> +   which will push to a branch with the same name as the current branch.
>> +   See the CONFIGURATION section below for more on `push.default`.
>> +
>> +As a safety measure, `git push` may fail if you haven't set an upstream
>> +for the current branch, depending on what `push.default` is set to.
>> +See the UPSTREAM BRANCHES section below for more on how to set and
>> +use upstreams.
>
> ... here is my attempt.
>
>     3. The `push.default` configuration. The default is `simple`,
>        which is a variant of `upstream`.  In either mode, "git push"
>        updates the configured upstream branch (see the UPSTREAM
>        BRANCHES section for more on how to set and use upstreams).
>        The 'simple' mode has an additional limitation that the name
>        of your configured upstream must be the same as your branch.
>
> (iow, I rolled the "As a safety measure" paragraph into 3. itself).
Junio C Hamano· Sep 26, 2025, 19:03 UTC · re: Julia Evans · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

"Julia Evans" <julia@jvns.ca> writes:
Show 15 quoted lines
>> In other words, the push.default=simple mode does not tell Git to
>> push to a branch with the same name.  Rather, as a variant of the
>> push.default=upstream mode, it tells Git to follow the same "push to
>> the upstream branch" rule, which requires you to configure your
>> upstream.  But the mode gives additional limit on the name of the
>> branch that can be set to upstream.
>
> I like the idea of explaining it as "push.default=simple uses the
> configured upstream branch, with the restriction that the upstream
> branch must have the same name".
>
> But as I learned from you earlier in this thread: https://lore.kernel.org/git/pull.1964.v2.git.1757703309.gitgitgadget@gmail.com/T/#m896f4a32ca462d69637b56f9bdfaa61e55e6b952
> push.default=simple will sometimes push the current branch
> to the remote branch with the same name even if there's no configured
> upstream branch.

It was not me teaching anybody, though. I was showing my puzzlement and confusion.

When b55e6775 (push: introduce new push.default mode "simple", 2012-04-24) introduced the "simple" mode, the intention was fairly clear:

    push: introduce new push.default mode "simple"
    
    When calling "git push" without argument, we want to allow Git to do
    something simple to explain and safe. push.default=matching is unsafe
    when used to push to shared repositories, and hard to explain to
    beginners in some contexts. It is debatable whether 'upstream' or
    'current' is the safest or the easiest to explain, so introduce a new
    mode called 'simple' that is the intersection of them: push to the
    upstream branch, but only if it has the same name remotely. If not, give
    an error that suggests the right command to push explicitely to
    'upstream' or 'current'.
    
    A question is whether to allow pushing when no upstream is configured. An
    argument in favor of allowing the push is that it makes the new mode work
    in more cases. On the other hand, refusing to push when no upstream is
    configured encourages the user to set the upstream, which will be
    beneficial on the next pull. Lacking better argument, we chose to deny
    the push, because it will be easier to change in the future if someone
    shows us wrong.
    
    Original-patch-by: Jeff King <peff@peff.net>
    Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

We did reject a "git push" (no other arguments) in an unconfigured repository using push.default=simple.

We must have _broken_ it along the way somewhere over the years.
In the output from
  $ git log --all-match --grep=push.default --grep=simple

there are a handful of changes that touch PUSH_DEFAULT_SIMPLE in ancient history; ed2b1829 (push: change `simple` to accommodate triangular workflows, 2013-06-19), seems to have broken the unconfigured case, which 00a6fa07 (push: truly use "simple" as default, not "upstream", 2014-11-26) tried to fix it, and then another commit e291c75a (remote.c: add branch_get_push, 2015-05-21) further tweaked on the triangular (i.e. the remote you are pushing to is different from the remote you are fetching from) workflow.

But that is long time ago; I do not think we can _fix_ the breakage as that would be a big behaviour change. If 'simple' works to update the branch with the same name as your current branch at the remote you cloned from without you having to do anything special, such a convinience is something the existing users we acquired over the past 10 years must have become very accustomed to already. We cannot break them.

    And that is my excuse for stopping to look into the detauls of
    these commits the above "git log" command found ;-)
Show 5 quoted lines
> So it seems more accurate to say that push.default.simple will push
> to the branch with the same name, with the restriction that you might
> have to set an upstream, because the branch must always have the
> same name, but whether or not you have to set an upstream depends
> on the situation.

Now, I am still confused as I was when I wrote the message you cited earlier.

Do we ever have a case where, with the "simple" mode, you have to set an upstream? You may have set an upstream in a way that is not compatible with the "simple" mode and need to fix it, but otherwise, it appears that the "simple" mode should always work for an unsuspecting user who does not configure their repository and remotes into some nonstandard shape.

And if so, perhaps we do not need any special warning/note to write for a place where we talk about "git push" generally (as opposed to where we talk about push.default=simple settings)?

Thanks.
Julia Evans· Sep 26, 2025, 22:27 UTC · re: Junio C Hamano · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

On Fri, Sep 26, 2025, at 3:03 PM, Junio C Hamano wrote:
Show 20 quoted lines
> "Julia Evans" <julia@jvns.ca> writes:
>
>>> In other words, the push.default=simple mode does not tell Git to
>>> push to a branch with the same name.  Rather, as a variant of the
>>> push.default=upstream mode, it tells Git to follow the same "push to
>>> the upstream branch" rule, which requires you to configure your
>>> upstream.  But the mode gives additional limit on the name of the
>>> branch that can be set to upstream.
>>
>> I like the idea of explaining it as "push.default=simple uses the
>> configured upstream branch, with the restriction that the upstream
>> branch must have the same name".
>>
>> But as I learned from you earlier in this thread: https://lore.kernel.org/git/pull.1964.v2.git.1757703309.gitgitgadget@gmail.com/T/#m896f4a32ca462d69637b56f9bdfaa61e55e6b952
>> push.default=simple will sometimes push the current branch
>> to the remote branch with the same name even if there's no configured
>> upstream branch.
>
> It was not me teaching anybody, though.  I was showing my puzzlement
> and confusion.

Oh, I'm glad I'm not the only one who's been confused about how `push.default=simple` behaves :)

Show 53 quoted lines
> When b55e6775 (push: introduce new push.default mode "simple",
> 2012-04-24) introduced the "simple" mode, the intention was fairly
> clear:
>
>     push: introduce new push.default mode "simple"
>    
>     When calling "git push" without argument, we want to allow Git to do
>     something simple to explain and safe. push.default=matching is unsafe
>     when used to push to shared repositories, and hard to explain to
>     beginners in some contexts. It is debatable whether 'upstream' or
>     'current' is the safest or the easiest to explain, so introduce a new
>     mode called 'simple' that is the intersection of them: push to the
>     upstream branch, but only if it has the same name remotely. If not, give
>     an error that suggests the right command to push explicitely to
>     'upstream' or 'current'.
>    
>     A question is whether to allow pushing when no upstream is configured. An
>     argument in favor of allowing the push is that it makes the new mode work
>     in more cases. On the other hand, refusing to push when no upstream is
>     configured encourages the user to set the upstream, which will be
>     beneficial on the next pull. Lacking better argument, we chose to deny
>     the push, because it will be easier to change in the future if someone
>     shows us wrong.
>    
>     Original-patch-by: Jeff King <peff@peff.net>
>     Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr>
>     Signed-off-by: Junio C Hamano <gitster@pobox.com>
>
> We did reject a "git push" (no other arguments) in an unconfigured
> repository using push.default=simple.
>
> We must have _broken_ it along the way somewhere over the years.
>
> In the output from
>
>   $ git log --all-match --grep=push.default --grep=simple
>
> there are a handful of changes that touch PUSH_DEFAULT_SIMPLE in
> ancient history; ed2b1829 (push: change `simple` to accommodate
> triangular workflows, 2013-06-19), seems to have broken the
> unconfigured case, which 00a6fa07 (push: truly use "simple" as
> default, not "upstream", 2014-11-26) tried to fix it, and then
> another commit e291c75a (remote.c: add branch_get_push, 2015-05-21)
> further tweaked on the triangular (i.e. the remote you are pushing
> to is different from the remote you are fetching from) workflow.
>
> But that is long time ago; I do not think we can _fix_ the breakage
> as that would be a big behaviour change.  If 'simple' works to
> update the branch with the same name as your current branch at the
> remote you cloned from without you having to do anything special,
> such a convinience is something the existing users we acquired over
> the past 10 years must have become very accustomed to already.  We
> cannot break them.
That makes sense, can’t break backwards compatibility.
Show 14 quoted lines
>     And that is my excuse for stopping to look into the detauls of
>     these commits the above "git log" command found ;-)
>
>> So it seems more accurate to say that push.default.simple will push
>> to the branch with the same name, with the restriction that you might
>> have to set an upstream, because the branch must always have the
>> same name, but whether or not you have to set an upstream depends
>> on the situation.
>
> Now, I am still confused as I was when I wrote the message you
> cited earlier.
>
> Do we ever have a case where, with the "simple" mode, you have to
> set an upstream?

Yes. If you clone a repository, create a new branch, and run `git push` (to push to `origin`), Git will complain that you haven’t set an upstream for that branch, like this:

    $ git push
    fatal: The current branch testtesttesttest has no upstream branch.
    To push the current branch and set the remote as upstream, use
    
        git push --set-upstream origin testtesttesttest
    To have this happen automatically for branches without a tracking
    upstream, see 'push.autoSetupRemote' in 'git help config'

I use `push.default=simple` and this has happened to me a lot in the past, personally I set `push.autoSetupRemote` to deal with this.

My best guess from my experimentation and from reading some of the commit messages/code is that the rules for how `push.default=simple` works are something like:

1. If the remote you're pushing to is the remote that `git pull`
   would normally pull from if run without any arguments,
   then require the user to set an upstream
   (with the idea that the remote is somehow "special"
   and should be protected from accidental pushes)
2. Otherwise, push to the branch to with the same name
   without requiring an upstream to be set

That said, the exact details of how push.default=simple works (ironically) seem complicated enough that I don't think it's worth documenting in detail at the beginning of the `git push` man page. I definitely haven't been able to fully understand what they are yet. Certainly it's true that sometimes you have to set an upstream and sometimes you don't.

To go back to the original text I suggested:
Show 8 quoted lines
> 3. The `push.default` configuration. The default is `push.default=simple`,
>    which will push to a branch with the same name as the current branch.
>    See the CONFIGURATION section below for more on `push.default`.
> 
> As a safety measure, `git push` may fail if you haven't set an upstream
> for the current branch, depending on what `push.default` is set to.
> See the UPSTREAM BRANCHES section below for more on how to set and
> use upstreams.

The words "may fail" are definitely vague, and I agree it doesn't feel good to give a vague explanation like this. But if we think the current behaviour is "broken" and hard to understand and that we have to keep it for backwards compatibility reasons, giving a slightly vague explanation (perhaps with a reference to where someone can read all the gritty details) might be the best path.

I do like the idea (that I think you mentioned before) of adding a very simple sentence like this near the beginning explaining what `git push origin main` does, since it's easy to explain, and someone could easily successfully start using `git push` without knowing any other information.

> `git push origin main` will push the local `main` branch to the `main`
branch on `origin`.
Junio C Hamano· Sep 26, 2025, 23:07 UTC · re: Julia Evans · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

"Julia Evans" <julia@jvns.ca> writes:
Show 38 quoted lines
> On Fri, Sep 26, 2025, at 3:03 PM, Junio C Hamano wrote:
>> "Julia Evans" <julia@jvns.ca> writes:
>>
>>>> In other words, the push.default=simple mode does not tell Git to
>>>> push to a branch with the same name.  Rather, as a variant of the
>>>> push.default=upstream mode, it tells Git to follow the same "push to
>>>> the upstream branch" rule, which requires you to configure your
>>>> upstream.  But the mode gives additional limit on the name of the
>>>> branch that can be set to upstream.
>>>
>>> I like the idea of explaining it as "push.default=simple uses the
>>> configured upstream branch, with the restriction that the upstream
>>> branch must have the same name".
>>>
>>> But as I learned from you earlier in this thread: https://lore.kernel.org/git/pull.1964.v2.git.1757703309.gitgitgadget@gmail.com/T/#m896f4a32ca462d69637b56f9bdfaa61e55e6b952
>>> push.default=simple will sometimes push the current branch
>>> to the remote branch with the same name even if there's no configured
>>> upstream branch.
>>
>> It was not me teaching anybody, though.  I was showing my puzzlement
>> and confusion.
>> Now, I am still confused as I was when I wrote the message you
>> cited earlier.
>>
>> Do we ever have a case where, with the "simple" mode, you have to
>> set an upstream?
>
> Yes. If you clone a repository, create a new branch, and run  `git push`
> (to push to `origin`), Git will complain that you haven’t set an upstream
> for that branch, like this:
>
>     $ git push
>     fatal: The current branch testtesttesttest has no upstream branch.
>     To push the current branch and set the remote as upstream, use
>     
>         git push --set-upstream origin testtesttesttest
>     To have this happen automatically for branches without a tracking
>     upstream, see 'push.autoSetupRemote' in 'git help config'

Hmph, that contradicts with the observation we had in the message you cited earlier, but it does reproduce for me as well. Puzzled again.

Show 9 quoted lines
> My best guess from my experimentation and from reading some
> of the commit messages/code is that the rules for how
> `push.default=simple` works are something like:
>
> 1. If the remote you're pushing to is the remote that `git pull`
>    would normally pull from if run without any arguments,
>    then require the user to set an upstream
>    (with the idea that the remote is somehow "special"
>    and should be protected from accidental pushes)
This is the traditional 'simple'
> 2. Otherwise, push to the branch to with the same name
>    without requiring an upstream to be set

This is what 'triangular' feature we saw earlier in the "git log" output in my message you are responding to had a few commits for.

> That said, the exact details of how push.default=simple works
> (ironically) seem complicated enough that I don't think it's worth
> documenting in detail at the beginning of the `git push` man page.
Totally agreed.
Show 17 quoted lines
> To go back to the original text I suggested:
>
>> 3. The `push.default` configuration. The default is `push.default=simple`,
>>    which will push to a branch with the same name as the current branch.
>>    See the CONFIGURATION section below for more on `push.default`.
>> 
>> As a safety measure, `git push` may fail if you haven't set an upstream
>> for the current branch, depending on what `push.default` is set to.
>> See the UPSTREAM BRANCHES section below for more on how to set and
>> use upstreams.
>
> The words "may fail" are definitely vague, and I agree it doesn't feel good
> to give a vague explanation like this. But if we think the current
> behaviour is "broken" and hard to understand and that we have to keep it for
> backwards compatibility reasons, giving a slightly vague explanation
> (perhaps with a reference to where someone can read all the gritty
> details) might be the best path.
OK.  Thanks for helping me think this through.
D. Ben Knoble· Sep 28, 2025, 21:38 UTC · re: Junio C Hamano · lore

Re: [PATCH v3 4/4] doc: git-push: clarify "what to push"

On Fri, Sep 26, 2025 at 7:07 PM Junio C Hamano <gitster@pobox.com> wrote:
Show 26 quoted lines
>
> "Julia Evans" <julia@jvns.ca> writes:
> > My best guess from my experimentation and from reading some
> > of the commit messages/code is that the rules for how
> > `push.default=simple` works are something like:
> >
> > 1. If the remote you're pushing to is the remote that `git pull`
> >    would normally pull from if run without any arguments,
> >    then require the user to set an upstream
> >    (with the idea that the remote is somehow "special"
> >    and should be protected from accidental pushes)
>
> This is the traditional 'simple'
>
>
> > 2. Otherwise, push to the branch to with the same name
> >    without requiring an upstream to be set
>
> This is what 'triangular' feature we saw earlier in the "git log"
> output in my message you are responding to had a few commits for.
>
> > That said, the exact details of how push.default=simple works
> > (ironically) seem complicated enough that I don't think it's worth
> > documenting in detail at the beginning of the `git push` man page.
>
> Totally agreed.
Seconded: Julia and I spent quite a bit of time in Discord trying to
piece this puzzle back together [1], and while I don't think we found
_all_ the commits you listed, we found most of them. My summary was
> I think the logic is:
>
> - pushing to the same remote you pull from? Only if @{upstream} is set (?? and maybe something about branch name matching, i don't remember),
> - pushing somewhere else? Pushes to destination=same name
[1]: https://discord.com/channels/1042895022950994071/1412969828066787462
Getting a clear picture _somewhere_ of this default would probably be nice.
-- 
D. Ben Knoble
D. Ben Knoble· Sep 23, 2025, 17:56 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v3 0/4] doc: git-push: clarify DESCRIPTION section

On Tue, Sep 23, 2025 at 1:44 PM Julia Evans via GitGitGadget <gitgitgadget@gmail.com> wrote:

Show 179 quoted lines
>
> I surveyed 16 Git users about the git push man page. Here's a rewrite of the
> DESCRIPTION section and the definition of <refspec> based on the feedback.
> The goal is to clarify it while communicating the same information. The most
> common piece of feedback was that folks didn't understand what the term
> "ref" means. Most of the users who said they did not understand the term
> "ref" have been using Git for 10+ years.
>
> changes in v2:
>
>  * The biggest change is to add a new UPSTREAM BRANCHES section to explain
>    what an upstream is
>  * Drop the "refspec" changes from this patch series, I've made revisions to
>    them based on the comments here but I felt like this was getting too big.
>  * Added some backticks `` that I'd missed, from Ben's review
>  * From Junio's review, "The current branch must have a configured upstream
>    with the same name, so this will fail when pushing a new branch" was not
>    true, so replace it with a less detailed but hopefully true statement.
>    After a very long conversation with Ben I realized that actually
>    push.default=simple's behaviour is not really that simple (perhaps I
>    should think of it as more "safe" than "simple", since "current" seems
>    simpler), so it's more realistic to refer any questions to the
>    CONFIGURATION section which describes the behaviour in more detail.
>  * Rewrite all the commits to explain the problem they're trying to solve &
>    thinking behind them in more detail. Let me know if I added too much /
>    not enough detail.
>
> changes in v3:
>
>  * mention that git push also needs to send data in addition to updating the
>    branch, from Junio's review
>  * fix a newline, from Junio's review
>  * un-rename urls-remotes.adoc, from Junio's review
>  * mention pushRemote and git checkout in the UPSTREAM BRANCHES section and
>    be clearer about what's meant by "the relationship between the current
>    branch and the upstream", from Junio's review
>  * fix AsciiDoc formatting issue, from Junio's review
>
> Julia Evans (4):
>   doc: git-push: clarify intro
>   doc: add an UPSTREAM BRANCHES section to pull/push/fetch
>   doc: git-push: clarify "where to push"
>   doc: git-push: clarify "what to push"
>
>  Documentation/git-push.adoc     | 43 +++++++++++++++++---------------
>  Documentation/urls-remotes.adoc | 44 ++++++++++++++++++++++++++++++---
>  2 files changed, 64 insertions(+), 23 deletions(-)
>
>
> base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1964%2Fjvns%2Fclarify-push-v3
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1964/jvns/clarify-push-v3
> Pull-Request: https://github.com/gitgitgadget/git/pull/1964
>
> Range-diff vs v2:
>
>  1:  270edd2b00 ! 1:  2870c77e80 doc: git-push: clarify intro
>      @@ Documentation/git-push.adoc: SYNOPSIS
>       -every time you push into it, by setting up 'hooks' there.  See
>       -documentation for linkgit:git-receive-pack[1].
>       +Updates one or more branches, tags, or other references in a remote
>      -+repository from your local repository.
>      ++repository from your local repository, and sends all necessary data
>      ++that isn't already on the remote.
>
>        When the command line does not specify where to push with the
>        `<repository>` argument, `branch.*.remote` configuration for the
>      @@ Documentation/git-push.adoc: corresponding upstream branch, but as a safety meas
>       +You can make interesting things happen to a repository
>       +every time you push into it, by setting up 'hooks' there.  See
>       +documentation for linkgit:git-receive-pack[1].
>      ++
>
>        OPTIONS[[OPTIONS]]
>        ------------------
>  2:  0ec629d403 ! 2:  3ecfb5c3a6 doc: add an UPSTREAM BRANCHES section to pull/push/fetch
>      @@ Commit message
>
>           Signed-off-by: Julia Evans <julia@jvns.ca>
>
>      - ## Documentation/git-fetch.adoc ##
>      -@@ Documentation/git-fetch.adoc: include::pull-fetch-param.adoc[]
>      -  Read refspecs, one per line, from stdin in addition to those provided
>      -  as arguments. The "tag <name>" format is not supported.
>      -
>      --include::urls-remotes.adoc[]
>      -+include::urls-remotes-upstreams.adoc[]
>      -
>      -
>      - CONFIGURED REMOTE-TRACKING BRANCHES[[CRTB]]
>      -
>      - ## Documentation/git-pull.adoc ##
>      -@@ Documentation/git-pull.adoc: include::fetch-options.adoc[]
>      -
>      - include::pull-fetch-param.adoc[]
>      -
>      --include::urls-remotes.adoc[]
>      -+include::urls-remotes-upstreams.adoc[]
>      -
>      - include::merge-strategies.adoc[]
>      -
>      -
>      - ## Documentation/git-push.adoc ##
>      -@@ Documentation/git-push.adoc: further recursion will occur. In this case, "only" is treated as "on-demand".
>      - --ipv6::
>      -  Use IPv6 addresses only, ignoring IPv4 addresses.
>      -
>      --include::urls-remotes.adoc[]
>      -+include::urls-remotes-upstreams.adoc[]
>      -
>      - OUTPUT
>      - ------
>      -
>      - ## Documentation/urls-remotes.adoc => Documentation/urls-remotes-upstreams.adoc ##
>      -@@ Documentation/urls-remotes-upstreams.adoc: git push uses:
>      + ## Documentation/urls-remotes.adoc ##
>      +@@ Documentation/urls-remotes.adoc: git push uses:
>         HEAD:refs/heads/<head>
>        ------------
>
>      @@ Documentation/urls-remotes-upstreams.adoc: git push uses:
>       +Git defaults to using the upstream branch for remote operations, for example:
>       +
>       +* It's the default for `git pull` or `git fetch` with no arguments
>      -+* It's sometimes the default for `git push` with no arguments. See the
>      -+  `push.default` section of linkgit:git-config[1] for the details.
>      -+* `git status` and `git branch -v` will show the
>      -+  relationship between the current branch and the upstream,
>      -+  for example "Your branch is up to date with origin/main"
>      ++* It's the default for `git push` with no arguments, with some exceptions.
>      ++  For example, you can use the `branch.<name>.pushRemote` option to push
>      ++  to a different remote than you pull from, and by default with
>      ++  `push.default=simple` the upstream branch you configure must have
>      ++  the same name.
>      ++* Various commands, including `git checkout` and `git status`, will
>      ++  show you how many commits have been added to your current branch and
>      ++  the upstream since you forked from it, for example "Your branch and
>      ++  'origin/main' have diverged, and have 2 and 3 different commits each
>      ++  respectively"
>       +
>       +The upstream is stored in `.git/config`, in the "remote" and "merge"
>       +fields. For example, if `main`'s upstream is `origin/main`:
>       +
>      -+```
>      -+[branch "main"]
>      -+   remote = origin
>      -+   merge = refs/heads/main
>      -+```
>      ++ [branch "main"]
>      ++    remote = origin
>      ++    merge = refs/heads/main
>       +
>       +You can set an upstream branch explicitly with
>       +`git push --set-upstream <remote> <branch>` or `git branch --track`,
>  3:  374740c678 ! 3:  bfd6072983 doc: git-push: clarify "where to push"
>      @@ Commit message
>           doc: git-push: clarify "where to push"
>
>           Be clearer about what we're describing ("which repository" instead of
>      -    "what to push"), and start with a positive "try X, then Y, then Z"
>      +    "where to push"), and start with a positive "try X, then Y, then Z"
>           instead of a negative ("if X is not specified..").
>
>           Signed-off-by: Julia Evans <julia@jvns.ca>
>
>        ## Documentation/git-push.adoc ##
>      -@@ Documentation/git-push.adoc: DESCRIPTION
>      - Updates one or more branches, tags, or other references in a remote
>      - repository from your local repository.
>      +@@ Documentation/git-push.adoc: Updates one or more branches, tags, or other references in a remote
>      + repository from your local repository, and sends all necessary data
>      + that isn't already on the remote.
>
>       -When the command line does not specify where to push with the
>       -`<repository>` argument, `branch.*.remote` configuration for the
>  4:  59732f1e47 = 4:  be6453d010 doc: git-push: clarify "what to push"
>
> --
> gitgitgadget
Range-diff looks good to me. Thanks Julia!
-- 
D. Ben Knoble
Julia Evans via GitGitGadget· Sep 30, 2025, 19:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v4 0/5] doc: git-push: clarify DESCRIPTION section

I surveyed 16 Git users about the git push man page. Here's a rewrite of the DESCRIPTION section and the definition of <refspec> based on the feedback. The goal is to clarify it while communicating the same information. The most common piece of feedback was that folks didn't understand what the term "ref" means. Most of the users who said they did not understand the term "ref" have been using Git for 10+ years.

changes in v2:
 * The biggest change is to add a new UPSTREAM BRANCHES section to explain
   what an upstream is
 * Drop the "refspec" changes from this patch series, I've made revisions to
   them based on the comments here but I felt like this was getting too big.
 * Added some backticks `` that I'd missed, from Ben's review
 * From Junio's review, "The current branch must have a configured upstream
   with the same name, so this will fail when pushing a new branch" was not
   true, so replace it with a less detailed but hopefully true statement.
   After a very long conversation with Ben I realized that actually
   push.default=simple's behaviour is not really that simple (perhaps I
   should think of it as more "safe" than "simple", since "current" seems
   simpler), so it's more realistic to refer any questions to the
   CONFIGURATION section which describes the behaviour in more detail.
 * Rewrite all the commits to explain the problem they're trying to solve &
   thinking behind them in more detail. Let me know if I added too much /
   not enough detail.
changes in v3:
 * mention that git push also needs to send data in addition to updating the
   branch, from Junio's review
 * fix a newline, from Junio's review
 * un-rename urls-remotes.adoc, from Junio's review
 * mention pushRemote and git checkout in the UPSTREAM BRANCHES section and
   be clearer about what's meant by "the relationship between the current
   branch and the upstream", from Junio's review
 * fix AsciiDoc formatting issue, from Junio's review
changes in v4:
 * Add "the simplest way to push is git push <remote> <branch>" at the
   beginning since (as discussed) this is the form of git push that's
   easiest to explain.
 * Remove "as a safety measure" since (as discussed with Junio) the reason
   that git push sometimes requires you to set an upstream is very
   confusing, and "as a safety measure..." makes it sound more principled
   than it is. Also update the commit message to say that the previous
   explanation was not describing push.default=simple's behaviour
   accurately.
 * Reword "To decide which repository to push to..." because I felt like it
   was still phrased in a clunky way.
 * Make UPSTREAM BRANCHES and CONFIGURATION into actual links in the HTML
   docs
 * Fix formatting in UPSTREAM BRANCHES section, from Junio's review
 * Fix some commit message mistakes, from Junio's review
Julia Evans (5):
  doc: git-push: clarify intro
  doc: add an UPSTREAM BRANCHES section to pull/push/fetch
  doc: git-push: clarify "where to push"
  doc: git-push: clarify "what to push"
  doc: git-push: Add explanation of `git push origin main`
 Documentation/git-push.adoc     | 47 ++++++++++++++++++---------------
 Documentation/urls-remotes.adoc | 43 ++++++++++++++++++++++++++++--
 2 files changed, 67 insertions(+), 23 deletions(-)
base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1964%2Fjvns%2Fclarify-push-v4
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1964/jvns/clarify-push-v4
Pull-Request: https://github.com/gitgitgadget/git/pull/1964
Range-diff vs v3:
 1:  2870c77e80 = 1:  d3160fb0af doc: git-push: clarify intro
 2:  3ecfb5c3a6 ! 2:  69825d4634 doc: add an UPSTREAM BRANCHES section to pull/push/fetch
     @@ Commit message
      
          Since the `git pull`, `git push`, and `git fetch` man pages already
          include sections on REMOTES and the syntax for URLs, add a section on
     -    UPSTREAM BRANCHES to `urls-remotes.adoc` and rename it to
     -    `urls-remotes-upstreams.adoc`. That's an awkward name but at least it's
     -    clear what's in the file.
     +    UPSTREAM BRANCHES to `urls-remotes.adoc`.
      
          In the new UPSTREAM BRANCHES section, cover the various ways that
          upstreams branches are automatically set in Git, since users may
     @@ Commit message
      
          A terminology note: Git uses two terms for this concept:
      
     -    - "tracking" as in "the current branch is _tracking_ some remote"
     +    - "tracking" as in "the tracking information for the 'foo' branch"
            or the `--track` option to `git branch`
          - "upstream" or "upstream branch", as in `git push --set-upstream`.
            This term is also used in the `git rebase` man page to refer to the
     @@ Commit message
      
       ## Documentation/urls-remotes.adoc ##
      @@ Documentation/urls-remotes.adoc: git push uses:
     - 	HEAD:refs/heads/<head>
       ------------
       
     --
     + 
      -
      -
      +UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
     @@ Documentation/urls-remotes.adoc: git push uses:
      +Branches in Git can optionally have an upstream remote branch.
      +Git defaults to using the upstream branch for remote operations, for example:
      +
     -+* It's the default for `git pull` or `git fetch` with no arguments
     ++* It's the default for `git pull` or `git fetch` with no arguments.
      +* It's the default for `git push` with no arguments, with some exceptions.
      +  For example, you can use the `branch.<name>.pushRemote` option to push
      +  to a different remote than you pull from, and by default with
     @@ Documentation/urls-remotes.adoc: git push uses:
      +  show you how many commits have been added to your current branch and
      +  the upstream since you forked from it, for example "Your branch and
      +  'origin/main' have diverged, and have 2 and 3 different commits each
     -+  respectively"
     ++  respectively".
      +
      +The upstream is stored in `.git/config`, in the "remote" and "merge"
      +fields. For example, if `main`'s upstream is `origin/main`:
 3:  bfd6072983 ! 3:  244c35ef2b doc: git-push: clarify "where to push"
     @@ Metadata
       ## Commit message ##
          doc: git-push: clarify "where to push"
      
     -    Be clearer about what we're describing ("which repository" instead of
     -    "where to push"), and start with a positive "try X, then Y, then Z"
     -    instead of a negative ("if X is not specified..").
     +    It's not obvious that "`branch.*.remote` configuration"` refers to the
     +    upstream, so say "upstream" instead.
     +
     +    The sentence is also quite hard to parse right now, use "defaults to" to
     +    simplify it.
      
          Signed-off-by: Julia Evans <julia@jvns.ca>
      
     @@ Documentation/git-push.adoc: Updates one or more branches, tags, or other refere
      -`<repository>` argument, `branch.*.remote` configuration for the
      -current branch is consulted to determine where to push.  If the
      -configuration is missing, it defaults to 'origin'.
     -+To decide which repository to push to, Git uses the `<repository>`
     -+argument (for example `git push dev`), then if that's not specified the
     -+upstream configuration for the current branch, and then defaults
     -+to `origin`.
     ++The `<repository>` argument defaults to the upstream for the current branch,
     ++or `origin` if there's no configured upstream.
       
       When the command line does not specify what to push with `<refspec>...`
       arguments or `--all`, `--mirror`, `--tags` options, the command finds
 4:  be6453d010 ! 4:  c1d4ea8d27 doc: git-push: clarify "what to push"
     @@ Commit message
          * not understanding what the term "upstream" means in Git
            ("are branches tracked by some system besides their names?"")
      
     -    Address all of these by using a numbered "in order of precedence" list
     -    (similar to the previous commit), by giving a little bit of context
     -    around "upstream branch": it's something that you may have to set
     -    explicitly, and referring to the new UPSTREAM BRANCHES section.
     +    Also, the current explanation of `push.default=simple` ("the
     +    current branch is pushed to the corresponding upstream branch, but
     +    as a safety measure, the push is aborted if the upstream branch
     +    does not have the same  name as the local one.") is not accurate:
     +    `push.default=simple` does not always require you to set a corresponding
     +    upstream branch.
     +
     +    Address all of these by
     +
     +    * using a numbered "in order of precedence" list
     +    * giving a more accurate explanation of how `push.default=simple` works
     +    * giving a little bit of context around "upstream branch": it's
     +      something that you may have to set explicitly
     +    * referring to the new UPSTREAM BRANCHES section
      
          The default behaviour is still discussed pretty late but it should be
          easier to skim now to get to the relevant information.
      
     +    In "`git push` may fail if...",  I'm intentionally being vague about
     +    what exactly `git push` does, because (as discussed on the mailing list)
     +    the behaviour of `push.default=simple` is very confusing, perhaps broken,
     +    and certainly not worth trying to explain in an introductory context.
     +    `push.default.simple` sometimes requires you to set an upstream and
     +    sometimes doesn't and the exact conditions under which it does/doesn't
     +    are hard to describe.
     +
          Signed-off-by: Julia Evans <julia@jvns.ca>
      
       ## Documentation/git-push.adoc ##
     -@@ Documentation/git-push.adoc: argument (for example `git push dev`), then if that's not specified the
     - upstream configuration for the current branch, and then defaults
     - to `origin`.
     +@@ Documentation/git-push.adoc: that isn't already on the remote.
     + The `<repository>` argument defaults to the upstream for the current branch,
     + or `origin` if there's no configured upstream.
       
      -When the command line does not specify what to push with `<refspec>...`
      -arguments or `--all`, `--mirror`, `--tags` options, the command finds
     @@ Documentation/git-push.adoc: argument (for example `git push dev`), then if that
      +2. The `remote.*.push` configuration for the repository being pushed to
      +3. The `push.default` configuration. The default is `push.default=simple`,
      +   which will push to a branch with the same name as the current branch.
     -+   See the CONFIGURATION section below for more on `push.default`.
     ++   See the <<CONFIGURATION,CONFIGURATION>> section below for more on `push.default`.
      +
     -+As a safety measure, `git push` may fail if you haven't set an upstream
     -+for the current branch, depending on what `push.default` is set to.
     -+See the UPSTREAM BRANCHES section below for more on how to set and
     -+use upstreams.
     ++`git push` may fail if you haven't set an upstream for the current branch,
     ++depending on what `push.default` is set to.
     ++See the <<UPSTREAM-BRANCHES,UPSTREAM BRANCHES>> section below for more
     ++on how to set and use upstreams.
       
       You can make interesting things happen to a repository
       every time you push into it, by setting up 'hooks' there.  See
     +@@ Documentation/git-push.adoc: a `git gc` command on the origin repository.
     + 
     + include::transfer-data-leaks.adoc[]
     + 
     +-CONFIGURATION
     ++CONFIGURATION[[CONFIGURATION]]
     + -------------
     + 
     + include::includes/cmd-config-section-all.adoc[]
 -:  ---------- > 5:  9435f0ce8d doc: git-push: Add explanation of `git push origin main`
-- 
gitgitgadget
Julia Evans via GitGitGadget· Sep 30, 2025, 19:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v4 1/5] doc: git-push: clarify intro

From: Julia Evans <julia@jvns.ca>

From user feedback, 5 users are unsure what "ref" and/or "objects" means in this context. 3 users said they don't know what "complete the refs" means.

Many users also commented that receive hooks do not seem like the most important thing to know about `git push`, and that this information should not be the second sentence in the man page.

Use more familiar language to make it more accessible to users who do not know what a "ref" is and move the "hooks" comment to the end.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
Show changes to Documentation/git-push.adoc +7 −6
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index d1978650d6..25d972f248 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -19,12 +19,9 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Updates remote refs using local refs, while sending objects
-necessary to complete the given refs.
-
-You can make interesting things happen to a repository
-every time you push into it, by setting up 'hooks' there.  See
-documentation for linkgit:git-receive-pack[1].
+Updates one or more branches, tags, or other references in a remote
+repository from your local repository, and sends all necessary data
+that isn't already on the remote.
 
 When the command line does not specify where to push with the
 `<repository>` argument, `branch.*.remote` configuration for the
@@ -44,6 +41,10 @@ corresponding upstream branch, but as a safety measure, the push is
 aborted if the upstream branch does not have the same name as the
 local one.
 
+You can make interesting things happen to a repository
+every time you push into it, by setting up 'hooks' there.  See
+documentation for linkgit:git-receive-pack[1].
+
 
 OPTIONS[[OPTIONS]]
 ------------------
-- 
gitgitgadget
Julia Evans via GitGitGadget· Sep 30, 2025, 19:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v4 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

From: Julia Evans <julia@jvns.ca>

From user feedback: one user mentioned that they don't know what the term "upstream branch" means. As far as I can tell, the most complete description is under the `--track` option in `git branch`. Upstreams are an important concept in Git and the `git branch` man page is not an obvious place for that information to live.

There's also a very terse description of "upstream branch" in the glossary that's missing a lot of key information, like the fact that the upstream is used by `git status` and `git pull`, as well as a description in `git-config` in `branch.<name>.remote` which doesn't explain the relationship to `git status` either.

Since the `git pull`, `git push`, and `git fetch` man pages already include sections on REMOTES and the syntax for URLs, add a section on UPSTREAM BRANCHES to `urls-remotes.adoc`.

In the new UPSTREAM BRANCHES section, cover the various ways that upstreams branches are automatically set in Git, since users may mistakenly think that their branch does not have an upstream branch if they didn't explicitly set one.

A terminology note: Git uses two terms for this concept:
- "tracking" as in "the tracking information for the 'foo' branch"
  or the `--track` option to `git branch`
- "upstream" or "upstream branch", as in `git push --set-upstream`.
  This term is also used in the `git rebase` man page to refer to the
  first argument to `git rebase`, as well as in `git pull` to refer to
  the branch which is going to be merged into the current branch ("merge
  the upstream branch into the current branch")

Use "upstream branch" as a heading for this concept even though the term "upstream branch" is not always used strictly in the sense of "the tracking information for the current branch". "Upstream" is used much more often than "tracking" in the Git docs to refer to this concept and the goal is to help users understand the docs.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/urls-remotes.adoc | 43 +++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)
Show changes to Documentation/urls-remotes.adoc +41 −2
diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes.adoc
index 9b10151198..dba5adeb58 100644
--- a/Documentation/urls-remotes.adoc
+++ b/Documentation/urls-remotes.adoc
@@ -92,5 +92,44 @@ git push uses:
 ------------
 
 
-
-
+UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
+--------------------------------------
+
+Branches in Git can optionally have an upstream remote branch.
+Git defaults to using the upstream branch for remote operations, for example:
+
+* It's the default for `git pull` or `git fetch` with no arguments.
+* It's the default for `git push` with no arguments, with some exceptions.
+  For example, you can use the `branch.<name>.pushRemote` option to push
+  to a different remote than you pull from, and by default with
+  `push.default=simple` the upstream branch you configure must have
+  the same name.
+* Various commands, including `git checkout` and `git status`, will
+  show you how many commits have been added to your current branch and
+  the upstream since you forked from it, for example "Your branch and
+  'origin/main' have diverged, and have 2 and 3 different commits each
+  respectively".
+
+The upstream is stored in `.git/config`, in the "remote" and "merge"
+fields. For example, if `main`'s upstream is `origin/main`:
+
+	[branch "main"]
+	   remote = origin
+	   merge = refs/heads/main
+
+You can set an upstream branch explicitly with
+`git push --set-upstream <remote> <branch>` or `git branch --track`,
+but Git will often automatically set the upstream for you, for example:
+
+* When you clone a repository, Git will automatically set the upstream
+  for the default branch.
+* If you have the `push.autoSetupRemote` configuration option set,
+  `git push` will automatically set the upstream the first time you push
+  a branch.
+* Checking out a remote-tracking branch with `git checkout <branch>`
+  will automatically create a local branch with that name and set
+  the upstream to the remote branch.
+
+[NOTE]
+Upstream branches are sometimes referred to as "tracking information",
+as in "set the branch's tracking information".
-- 
gitgitgadget
Junio C Hamano· Sep 30, 2025, 23:39 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v4 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
> +You can set an upstream branch explicitly with
> +`git push --set-upstream <remote> <branch>` or `git branch --track`,

I am wondering if this confuses beginners, appearing as if the latter does not need any other command line arguments, as the former does say two pieces of information needs to be given.

Show 14 quoted lines
> +but Git will often automatically set the upstream for you, for example:
> +
> +* When you clone a repository, Git will automatically set the upstream
> +  for the default branch.
> +* If you have the `push.autoSetupRemote` configuration option set,
> +  `git push` will automatically set the upstream the first time you push
> +  a branch.
> +* Checking out a remote-tracking branch with `git checkout <branch>`
> +  will automatically create a local branch with that name and set
> +  the upstream to the remote branch.
> +
> +[NOTE]
> +Upstream branches are sometimes referred to as "tracking information",
> +as in "set the branch's tracking information".
Everything else looked great.  Thanks for working on this.
Julia Evans· Oct 3, 2025, 18:23 UTC · re: Junio C Hamano · lore

Re: [PATCH v4 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Tue, Sep 30, 2025, at 7:39 PM, Junio C Hamano wrote:
Show 8 quoted lines
> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
>> +You can set an upstream branch explicitly with
>> +`git push --set-upstream <remote> <branch>` or `git branch --track`,
>
> I am wondering if this confuses beginners, appearing as if the
> latter does not need any other command line arguments, as the former
> does say two pieces of information needs to be given.
That makes sense.

I tried to read the documentation for `git branch --track` to figure out how to give an example, but I found it very hard to understand how it's intended to be used since there are so many options for `--track=`.

Usually when I'm creating a new branch, I want to set an upstream which doesn't exist yet on the remote, and I couldn't figure out whether or not it's possible to do that with `git branch --track`.

My best idea right now is to delete the mention of `git branch --track` here if I can't figure out how it's intended to be used.

Junio C Hamano· Oct 3, 2025, 19:12 UTC · re: Julia Evans · lore

Re: [PATCH v4 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

"Julia Evans" <julia@jvns.ca> writes:
> My best idea right now is to delete the mention of `git branch --track`
> here if I can't figure out how it's intended to be used.
As we do not have to be exhausitive here, it is a good way out.
Jean-Noël AVILA· Oct 1, 2025, 17:30 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v4 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Tuesday, 30 September 2025 21:58:31 CEST Julia Evans via GitGitGadget wrote:

Show 45 quoted lines
> From: Julia Evans <julia@jvns.ca>
> 
> From user feedback: one user mentioned that they don't know what the
> term "upstream branch" means. As far as I can tell, the most complete
> description is under the `--track` option in `git branch`. Upstreams
> are an important concept in Git and the `git branch` man page is not an
> obvious place for that information to live.
> 
> There's also a very terse description of "upstream branch" in the
> glossary that's missing a lot of key information, like the fact that the
> upstream is used by `git status` and `git pull`, as well as a
> description in `git-config` in `branch.<name>.remote` which doesn't
> explain the relationship to `git status` either.
> 
> Since the `git pull`, `git push`, and `git fetch` man pages already
> include sections on REMOTES and the syntax for URLs, add a section on
> UPSTREAM BRANCHES to `urls-remotes.adoc`.
> 
> In the new UPSTREAM BRANCHES section, cover the various ways that
> upstreams branches are automatically set in Git, since users may
> mistakenly think that their branch does not have an upstream branch if
> they didn't explicitly set one.
> 
> A terminology note: Git uses two terms for this concept:
> 
> - "tracking" as in "the tracking information for the 'foo' branch"
>   or the `--track` option to `git branch`
> - "upstream" or "upstream branch", as in `git push --set-upstream`.
>   This term is also used in the `git rebase` man page to refer to the
>   first argument to `git rebase`, as well as in `git pull` to refer to
>   the branch which is going to be merged into the current branch ("merge
>   the upstream branch into the current branch")
> 
> Use "upstream branch" as a heading for this concept even though the term
> "upstream branch" is not always used strictly in the sense of "the
> tracking information for the current branch". "Upstream" is used much
> more often than "tracking" in the Git docs to refer to this concept and
> the goal is to help users understand the docs.
> 
> Signed-off-by: Julia Evans <julia@jvns.ca>
> ---
>  Documentation/urls-remotes.adoc | 43 +++++++++++++++++++++++++++++++--
>  1 file changed, 41 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-
remotes.adoc
Show 11 quoted lines
> index 9b10151198..dba5adeb58 100644
> --- a/Documentation/urls-remotes.adoc
> +++ b/Documentation/urls-remotes.adoc
> @@ -92,5 +92,44 @@ git push uses:
>  ------------
> 
> 
> -
> -
> +UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
> +--------------------------------------

Please do not put anchors on the same line as the paragraph. The anchor is attached to the paragraph (the block in asciidoc terminology) if it is not attached to an inline element. So it can appear just before the block with the same effect.

Additionally, this clears up the text from the anchor, which is safer for translation.

[[UPSTREAM-BRANCHES]] UPSTREAM BRANCHES

> +
> +Branches in Git can optionally have an upstream remote branch.
> +Git defaults to using the upstream branch for remote operations, for 
example:
Show 20 quoted lines
> +
> +* It's the default for `git pull` or `git fetch` with no arguments.
> +* It's the default for `git push` with no arguments, with some exceptions.
> +  For example, you can use the `branch.<name>.pushRemote` option to push
> +  to a different remote than you pull from, and by default with
> +  `push.default=simple` the upstream branch you configure must have
> +  the same name.
> +* Various commands, including `git checkout` and `git status`, will
> +  show you how many commits have been added to your current branch and
> +  the upstream since you forked from it, for example "Your branch and
> +  'origin/main' have diverged, and have 2 and 3 different commits each
> +  respectively".
> +
> +The upstream is stored in `.git/config`, in the "remote" and "merge"
> +fields. For example, if `main`'s upstream is `origin/main`:
> +
> +	[branch "main"]
> +	   remote = origin
> +	   merge = refs/heads/main
> +
Please mark the code block with a dedicated fence:
----
[branch "main"]
   remote = origin
   merge = refs/heads/main
----
using tabs may lead to issues if the text is modified later.
Show 16 quoted lines
> +You can set an upstream branch explicitly with
> +`git push --set-upstream <remote> <branch>` or `git branch --track`,
> +but Git will often automatically set the upstream for you, for example:
> +
> +* When you clone a repository, Git will automatically set the upstream
> +  for the default branch.
> +* If you have the `push.autoSetupRemote` configuration option set,
> +  `git push` will automatically set the upstream the first time you push
> +  a branch.
> +* Checking out a remote-tracking branch with `git checkout <branch>`
> +  will automatically create a local branch with that name and set
> +  the upstream to the remote branch.
> +
> +[NOTE]
> +Upstream branches are sometimes referred to as "tracking information",
> +as in "set the branch's tracking information".
Thanks
Julia Evans· Oct 3, 2025, 17:54 UTC · re: Jean-Noël AVILA · lore

Re: [PATCH v4 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

>> +UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
>> +--------------------------------------
>
> Please do not put anchors on the same line as the paragraph.

Thanks, will fix. I just copied that from elsewhere in the documentation, but I agree the anchors should be on the line above.

Show 17 quoted lines
>> +The upstream is stored in `.git/config`, in the "remote" and "merge"
>> +fields. For example, if `main`'s upstream is `origin/main`:
>> +
>> +	[branch "main"]
>> +	   remote = origin
>> +	   merge = refs/heads/main
>> +
>
> Please mark the code block with a dedicated fence:
>
> ----
> [branch "main"]
>    remote = origin
>    merge = refs/heads/main
> ----
>
> using tabs may lead to issues if the text is modified later.

Can do -- previously I was using backticks but they didn't work, so I switched to indenting it as discussed here: https://lore.kernel.org/git/xmqqqzw7arls.fsf@gitster.g/

But I can use ---- instead.

It might be useful to document both of those in the part of CodingGuidelines that explains documentation formatting, I don't see them there.

Julia Evans via GitGitGadget· Sep 30, 2025, 19:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v4 3/5] doc: git-push: clarify "where to push"

From: Julia Evans <julia@jvns.ca>

It's not obvious that "`branch.*.remote` configuration"` refers to the upstream, so say "upstream" instead.

The sentence is also quite hard to parse right now, use "defaults to" to simplify it.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
Show changes to Documentation/git-push.adoc +2 −4
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index 25d972f248..acdf25e5cd 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -23,10 +23,8 @@ Updates one or more branches, tags, or other references in a remote
 repository from your local repository, and sends all necessary data
 that isn't already on the remote.
 
-When the command line does not specify where to push with the
-`<repository>` argument, `branch.*.remote` configuration for the
-current branch is consulted to determine where to push.  If the
-configuration is missing, it defaults to 'origin'.
+The `<repository>` argument defaults to the upstream for the current branch,
+or `origin` if there's no configured upstream.
 
 When the command line does not specify what to push with `<refspec>...`
 arguments or `--all`, `--mirror`, `--tags` options, the command finds
-- 
gitgitgadget
Julia Evans via GitGitGadget· Sep 30, 2025, 19:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v4 4/5] doc: git-push: clarify "what to push"

From: Julia Evans <julia@jvns.ca>

From user feedback: 6 users says they found the "what to push" paragraphs confusing, for many different reasons, including:

* what does "..." in <refspec>... mean?
* "consult XXX configuration" is hard to parse
* it refers to the `git-config` man page even though the config
  information for `git push` is included in this man page under
  CONFIGURATION
* the default ("push to a branch with the same name") is what they use
  99% of the time, they would have expected it to appear earlier instead
  of at the very end
* not understanding what the term "upstream" means in Git
  ("are branches tracked by some system besides their names?"")

Also, the current explanation of `push.default=simple` ("the current branch is pushed to the corresponding upstream branch, but as a safety measure, the push is aborted if the upstream branch does not have the same name as the local one.") is not accurate: `push.default=simple` does not always require you to set a corresponding upstream branch.

Address all of these by
* using a numbered "in order of precedence" list
* giving a more accurate explanation of how `push.default=simple` works
* giving a little bit of context around "upstream branch": it's
  something that you may have to set explicitly
* referring to the new UPSTREAM BRANCHES section

The default behaviour is still discussed pretty late but it should be easier to skim now to get to the relevant information.

In "`git push` may fail if...", I'm intentionally being vague about what exactly `git push` does, because (as discussed on the mailing list) the behaviour of `push.default=simple` is very confusing, perhaps broken, and certainly not worth trying to explain in an introductory context. `push.default.simple` sometimes requires you to set an upstream and sometimes doesn't and the exact conditions under which it does/doesn't are hard to describe.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
Show changes to Documentation/git-push.adoc +15 −13
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index acdf25e5cd..2848cf2e1f 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -26,18 +26,20 @@ that isn't already on the remote.
 The `<repository>` argument defaults to the upstream for the current branch,
 or `origin` if there's no configured upstream.
 
-When the command line does not specify what to push with `<refspec>...`
-arguments or `--all`, `--mirror`, `--tags` options, the command finds
-the default `<refspec>` by consulting `remote.*.push` configuration,
-and if it is not found, honors `push.default` configuration to decide
-what to push (See linkgit:git-config[1] for the meaning of `push.default`).
-
-When neither the command-line nor the configuration specifies what to
-push, the default behavior is used, which corresponds to the `simple`
-value for `push.default`: the current branch is pushed to the
-corresponding upstream branch, but as a safety measure, the push is
-aborted if the upstream branch does not have the same name as the
-local one.
+To decide which branches, tags, or other refs to push, Git uses
+(in order of precedence):
+
+1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
+   or the `--all`, `--mirror`, or `--tags` options
+2. The `remote.*.push` configuration for the repository being pushed to
+3. The `push.default` configuration. The default is `push.default=simple`,
+   which will push to a branch with the same name as the current branch.
+   See the <<CONFIGURATION,CONFIGURATION>> section below for more on `push.default`.
+
+`git push` may fail if you haven't set an upstream for the current branch,
+depending on what `push.default` is set to.
+See the <<UPSTREAM-BRANCHES,UPSTREAM BRANCHES>> section below for more
+on how to set and use upstreams.
 
 You can make interesting things happen to a repository
 every time you push into it, by setting up 'hooks' there.  See
@@ -696,7 +698,7 @@ a `git gc` command on the origin repository.
 
 include::transfer-data-leaks.adoc[]
 
-CONFIGURATION
+CONFIGURATION[[CONFIGURATION]]
 -------------
 
 include::includes/cmd-config-section-all.adoc[]
-- 
gitgitgadget
Junio C Hamano· Sep 30, 2025, 21:01 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v4 4/5] doc: git-push: clarify "what to push"

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 14 quoted lines
> +To decide which branches, tags, or other refs to push, Git uses
> +(in order of precedence):
> +
> +1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
> +   or the `--all`, `--mirror`, or `--tags` options
> +2. The `remote.*.push` configuration for the repository being pushed to
> +3. The `push.default` configuration. The default is `push.default=simple`,
> +   which will push to a branch with the same name as the current branch.
> +   See the <<CONFIGURATION,CONFIGURATION>> section below for more on `push.default`.
> +
> +`git push` may fail if you haven't set an upstream for the current branch,
> +depending on what `push.default` is set to.
> +See the <<UPSTREAM-BRANCHES,UPSTREAM BRANCHES>> section below for more
> +on how to set and use upstreams.
Reads well, does not tell any lies, and I like it.
Show 7 quoted lines
> @@ -696,7 +698,7 @@ a `git gc` command on the origin repository.
>  
>  include::transfer-data-leaks.adoc[]
>  
> -CONFIGURATION
> +CONFIGURATION[[CONFIGURATION]]
>  -------------

Looking at what we have in previous steps (e.g., post context of 1/5, the title of the new section in 2/5), I think you'd need to elongate the underline.

Jean-Noël AVILA· Oct 1, 2025, 17:36 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v4 4/5] doc: git-push: clarify "what to push"

On Tuesday, 30 September 2025 21:58:33 CEST Julia Evans via GitGitGadget wrote:

Show 53 quoted lines
> From: Julia Evans <julia@jvns.ca>
> 
> From user feedback: 6 users says they found the "what to push"
> paragraphs confusing, for many different reasons, including:
> 
> * what does "..." in <refspec>... mean?
> * "consult XXX configuration" is hard to parse
> * it refers to the `git-config` man page even though the config
>   information for `git push` is included in this man page under
>   CONFIGURATION
> * the default ("push to a branch with the same name") is what they use
>   99% of the time, they would have expected it to appear earlier instead
>   of at the very end
> * not understanding what the term "upstream" means in Git
>   ("are branches tracked by some system besides their names?"")
> 
> Also, the current explanation of `push.default=simple` ("the
> current branch is pushed to the corresponding upstream branch, but
> as a safety measure, the push is aborted if the upstream branch
> does not have the same  name as the local one.") is not accurate:
> `push.default=simple` does not always require you to set a corresponding
> upstream branch.
> 
> Address all of these by
> 
> * using a numbered "in order of precedence" list
> * giving a more accurate explanation of how `push.default=simple` works
> * giving a little bit of context around "upstream branch": it's
>   something that you may have to set explicitly
> * referring to the new UPSTREAM BRANCHES section
> 
> The default behaviour is still discussed pretty late but it should be
> easier to skim now to get to the relevant information.
> 
> In "`git push` may fail if...",  I'm intentionally being vague about
> what exactly `git push` does, because (as discussed on the mailing list)
> the behaviour of `push.default=simple` is very confusing, perhaps broken,
> and certainly not worth trying to explain in an introductory context.
> `push.default.simple` sometimes requires you to set an upstream and
> sometimes doesn't and the exact conditions under which it does/doesn't
> are hard to describe.
> 
> Signed-off-by: Julia Evans <julia@jvns.ca>
> ---
>  Documentation/git-push.adoc | 28 +++++++++++++++-------------
>  1 file changed, 15 insertions(+), 13 deletions(-)
> 
> diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
> index acdf25e5cd..2848cf2e1f 100644
> --- a/Documentation/git-push.adoc
> +++ b/Documentation/git-push.adoc
> @@ -26,18 +26,20 @@ that isn't already on the remote.
>  The `<repository>` argument defaults to the upstream for the current 
branch,
Show 18 quoted lines
>  or `origin` if there's no configured upstream.
> 
> -When the command line does not specify what to push with `<refspec>...`
> -arguments or `--all`, `--mirror`, `--tags` options, the command finds
> -the default `<refspec>` by consulting `remote.*.push` configuration,
> -and if it is not found, honors `push.default` configuration to decide
> -what to push (See linkgit:git-config[1] for the meaning of `push.default`).
> -
> -When neither the command-line nor the configuration specifies what to
> -push, the default behavior is used, which corresponds to the `simple`
> -value for `push.default`: the current branch is pushed to the
> -corresponding upstream branch, but as a safety measure, the push is
> -aborted if the upstream branch does not have the same name as the
> -local one.
> +To decide which branches, tags, or other refs to push, Git uses
> +(in order of precedence):
> +
> +1. The `<refspec>` argument(s) (for example `main` in `git push origin 
main`)
Show 5 quoted lines
> +   or the `--all`, `--mirror`, or `--tags` options
> +2. The `remote.*.push` configuration for the repository being pushed to
> +3. The `push.default` configuration. The default is `push.default=simple`,
> +   which will push to a branch with the same name as the current branch.
> +   See the <<CONFIGURATION,CONFIGURATION>> section below for more on
Good: using the cross-reference with custom label is translator's friendly.  
Thank you.
Show 15 quoted lines
> `push.default`. +
> +`git push` may fail if you haven't set an upstream for the current branch,
> +depending on what `push.default` is set to.
> +See the <<UPSTREAM-BRANCHES,UPSTREAM BRANCHES>> section below for more
> +on how to set and use upstreams.
> 
>  You can make interesting things happen to a repository
>  every time you push into it, by setting up 'hooks' there.  See
> @@ -696,7 +698,7 @@ a `git gc` command on the origin repository.
> 
>  include::transfer-data-leaks.adoc[]
> 
> -CONFIGURATION
> +CONFIGURATION[[CONFIGURATION]]
>  -------------
Same remark concerning anchors.
Otherwise, LGTM
Julia Evans via GitGitGadget· Sep 30, 2025, 19:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v4 5/5] doc: git-push: Add explanation of `git push origin main`

From: Julia Evans <julia@jvns.ca>

What happens if you run `git push` without any arguments is actually extremely complex to explain, as discussed in the previous commit.

But it's very easy to explain what `git push <remote> <branch>` does, so start the man page by explaining what that does.

The hope is that someone could just stop reading the man page here and never learn anything else about `git push`, and that would be fine.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 4 ++++
 1 file changed, 4 insertions(+)
Show changes to Documentation/git-push.adoc +4 −0
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index 2848cf2e1f..c0e743d4a8 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -23,6 +23,10 @@ Updates one or more branches, tags, or other references in a remote
 repository from your local repository, and sends all necessary data
 that isn't already on the remote.
 
+The simplest way to push is `git push <remote> <branch>`.
+`git push origin main` will push the local `main` branch to the `main`
+branch on the remote named `origin`.
+
 The `<repository>` argument defaults to the upstream for the current branch,
 or `origin` if there's no configured upstream.
 
-- 
gitgitgadget
D. Ben Knoble· Oct 1, 2025, 22:29 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v4 5/5] doc: git-push: Add explanation of `git push origin main`

On Tue, Sep 30, 2025 at 3:58 PM Julia Evans via GitGitGadget <gitgitgadget@gmail.com> wrote:

Show 28 quoted lines
>
> From: Julia Evans <julia@jvns.ca>
>
> What happens if you run `git push` without any arguments is actually
> extremely complex to explain, as discussed in the previous commit.
>
> But it's very easy to explain what `git push <remote> <branch>` does, so
> start the man page by explaining what that does.
>
> The hope is that someone could just stop reading the man page here and
> never learn anything else about `git push`, and that would be fine.
>
> Signed-off-by: Julia Evans <julia@jvns.ca>
> ---
>  Documentation/git-push.adoc | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
> index 2848cf2e1f..c0e743d4a8 100644
> --- a/Documentation/git-push.adoc
> +++ b/Documentation/git-push.adoc
> @@ -23,6 +23,10 @@ Updates one or more branches, tags, or other references in a remote
>  repository from your local repository, and sends all necessary data
>  that isn't already on the remote.
>
> +The simplest way to push is `git push <remote> <branch>`.
> +`git push origin main` will push the local `main` branch to the `main`
> +branch on the remote named `origin`.

Perhaps "For example," to avoid starting with punctuation/commands? I'm not sure if that kind of thing is actually confusing for readers or not, though. If not, I'll stop recommending such changes.

-- 
D. Ben Knoble
Julia Evans· Oct 3, 2025, 17:58 UTC · re: D. Ben Knoble · lore

Re: [PATCH v4 5/5] doc: git-push: Add explanation of `git push origin main`

Show 7 quoted lines
>> +The simplest way to push is `git push <remote> <branch>`.
>> +`git push origin main` will push the local `main` branch to the `main`
>> +branch on the remote named `origin`.
>
> Perhaps "For example," to avoid starting with punctuation/commands?
> I'm not sure if that kind of thing is actually confusing for readers
> or not, though. If not, I'll stop recommending such changes.
I don't think I've ever been told by a reader that it's confusing.
D. Ben Knoble· Oct 1, 2025, 22:28 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v4 0/5] doc: git-push: clarify DESCRIPTION section

On Tue, Sep 30, 2025 at 3:58 PM Julia Evans via GitGitGadget <gitgitgadget@gmail.com> wrote:

Show 17 quoted lines
> changes in v4:
>
>  * Add "the simplest way to push is git push <remote> <branch>" at the
>    beginning since (as discussed) this is the form of git push that's
>    easiest to explain.
>  * Remove "as a safety measure" since (as discussed with Junio) the reason
>    that git push sometimes requires you to set an upstream is very
>    confusing, and "as a safety measure..." makes it sound more principled
>    than it is. Also update the commit message to say that the previous
>    explanation was not describing push.default=simple's behaviour
>    accurately.
>  * Reword "To decide which repository to push to..." because I felt like it
>    was still phrased in a clunky way.
>  * Make UPSTREAM BRANCHES and CONFIGURATION into actual links in the HTML
>    docs
>  * Fix formatting in UPSTREAM BRANCHES section, from Junio's review
>  * Fix some commit message mistakes, from Junio's review
Great work.
Show 32 quoted lines
>  4:  be6453d010 ! 4:  c1d4ea8d27 doc: git-push: clarify "what to push"
>      @@ Commit message
>           * not understanding what the term "upstream" means in Git
>             ("are branches tracked by some system besides their names?"")
>
>      -    Address all of these by using a numbered "in order of precedence" list
>      -    (similar to the previous commit), by giving a little bit of context
>      -    around "upstream branch": it's something that you may have to set
>      -    explicitly, and referring to the new UPSTREAM BRANCHES section.
>      +    Also, the current explanation of `push.default=simple` ("the
>      +    current branch is pushed to the corresponding upstream branch, but
>      +    as a safety measure, the push is aborted if the upstream branch
>      +    does not have the same  name as the local one.") is not accurate:
>      +    `push.default=simple` does not always require you to set a corresponding
>      +    upstream branch.
>      +
>      +    Address all of these by
>      +
>      +    * using a numbered "in order of precedence" list
>      +    * giving a more accurate explanation of how `push.default=simple` works
>      +    * giving a little bit of context around "upstream branch": it's
>      +      something that you may have to set explicitly
>      +    * referring to the new UPSTREAM BRANCHES section
>
>           The default behaviour is still discussed pretty late but it should be
>           easier to skim now to get to the relevant information.
>
>      +    In "`git push` may fail if...",  I'm intentionally being vague about
>      +    what exactly `git push` does, because (as discussed on the mailing list)
>      +    the behaviour of `push.default=simple` is very confusing, perhaps broken,
>      +    and certainly not worth trying to explain in an introductory context.
>      +    `push.default.simple` sometimes requires you to set an upstream and
Rather, push.default=simple?
-- 
D. Ben Knoble
Julia Evans via GitGitGadget· Oct 6, 2025, 18:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v5 0/5] doc: git-push: clarify DESCRIPTION section

I surveyed 16 Git users about the git push man page. Here's a rewrite of the DESCRIPTION section and the definition of <refspec> based on the feedback. The goal is to clarify it while communicating the same information. The most common piece of feedback was that folks didn't understand what the term "ref" means. Most of the users who said they did not understand the term "ref" have been using Git for 10+ years.

changes in v2:
 * The biggest change is to add a new UPSTREAM BRANCHES section to explain
   what an upstream is
 * Drop the "refspec" changes from this patch series, I've made revisions to
   them based on the comments here but I felt like this was getting too big.
 * Added some backticks `` that I'd missed, from Ben's review
 * From Junio's review, "The current branch must have a configured upstream
   with the same name, so this will fail when pushing a new branch" was not
   true, so replace it with a less detailed but hopefully true statement.
   After a very long conversation with Ben I realized that actually
   push.default=simple's behaviour is not really that simple (perhaps I
   should think of it as more "safe" than "simple", since "current" seems
   simpler), so it's more realistic to refer any questions to the
   CONFIGURATION section which describes the behaviour in more detail.
 * Rewrite all the commits to explain the problem they're trying to solve &
   thinking behind them in more detail. Let me know if I added too much /
   not enough detail.
changes in v3:
 * mention that git push also needs to send data in addition to updating the
   branch, from Junio's review
 * fix a newline, from Junio's review
 * un-rename urls-remotes.adoc, from Junio's review
 * mention pushRemote and git checkout in the UPSTREAM BRANCHES section and
   be clearer about what's meant by "the relationship between the current
   branch and the upstream", from Junio's review
 * fix AsciiDoc formatting issue, from Junio's review
changes in v4:
 * Add "the simplest way to push is git push <remote> <branch>" at the
   beginning since (as discussed) this is the form of git push that's
   easiest to explain.
 * Remove "as a safety measure" since (as discussed with Junio) the reason
   that git push sometimes requires you to set an upstream is very
   confusing, and "as a safety measure..." makes it sound more principled
   than it is. Also update the commit message to say that the previous
   explanation was not describing push.default=simple's behaviour
   accurately.
 * Reword "To decide which repository to push to..." because I felt like it
   was still phrased in a clunky way.
 * Make UPSTREAM BRANCHES and CONFIGURATION into actual links in the HTML
   docs
 * Fix formatting in UPSTREAM BRANCHES section, from Junio's review
 * Fix some commit message mistakes, from Junio's review
changes in v5:
 * remove a bad example of git branch --track, from Junio's review
 * fix some formatting issues, from Jean-Noël's review
Julia Evans (5):
  doc: git-push: clarify intro
  doc: add an UPSTREAM BRANCHES section to pull/push/fetch
  doc: git-push: clarify "where to push"
  doc: git-push: clarify "what to push"
  doc: git-push: Add explanation of `git push origin main`
 Documentation/git-push.adoc     | 46 +++++++++++++++++++--------------
 Documentation/urls-remotes.adoc | 42 ++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+), 20 deletions(-)
base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1964%2Fjvns%2Fclarify-push-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1964/jvns/clarify-push-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/1964
Range-diff vs v4:
 1:  d3160fb0af = 1:  4811ce1c86 doc: git-push: clarify intro
 2:  69825d4634 ! 2:  10a9718421 doc: add an UPSTREAM BRANCHES section to pull/push/fetch
     @@ Documentation/urls-remotes.adoc: git push uses:
       ------------
       
       
     --
     --
     -+UPSTREAM BRANCHES[[UPSTREAM-BRANCHES]]
     -+--------------------------------------
     ++[[UPSTREAM-BRANCHES]]
     ++UPSTREAM BRANCHES
     ++-----------------
      +
      +Branches in Git can optionally have an upstream remote branch.
      +Git defaults to using the upstream branch for remote operations, for example:
     @@ Documentation/urls-remotes.adoc: git push uses:
      +
      +The upstream is stored in `.git/config`, in the "remote" and "merge"
      +fields. For example, if `main`'s upstream is `origin/main`:
     -+
     -+	[branch "main"]
     -+	   remote = origin
     -+	   merge = refs/heads/main
     -+
     + 
     ++------------
     ++[branch "main"]
     ++   remote = origin
     ++   merge = refs/heads/main
     ++------------
     + 
      +You can set an upstream branch explicitly with
     -+`git push --set-upstream <remote> <branch>` or `git branch --track`,
     ++`git push --set-upstream <remote> <branch>`
      +but Git will often automatically set the upstream for you, for example:
      +
      +* When you clone a repository, Git will automatically set the upstream
 3:  244c35ef2b = 3:  336023fbf1 doc: git-push: clarify "where to push"
 4:  c1d4ea8d27 ! 4:  8e82c508f6 doc: git-push: clarify "what to push"
     @@ Documentation/git-push.adoc: a `git gc` command on the origin repository.
       
       include::transfer-data-leaks.adoc[]
       
     --CONFIGURATION
     -+CONFIGURATION[[CONFIGURATION]]
     ++[[CONFIGURATION]]
     + CONFIGURATION
       -------------
       
     - include::includes/cmd-config-section-all.adoc[]
 5:  9435f0ce8d = 5:  ddeb8ecabe doc: git-push: Add explanation of `git push origin main`
-- 
gitgitgadget
Julia Evans via GitGitGadget· Oct 6, 2025, 18:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v5 1/5] doc: git-push: clarify intro

From: Julia Evans <julia@jvns.ca>

From user feedback, 5 users are unsure what "ref" and/or "objects" means in this context. 3 users said they don't know what "complete the refs" means.

Many users also commented that receive hooks do not seem like the most important thing to know about `git push`, and that this information should not be the second sentence in the man page.

Use more familiar language to make it more accessible to users who do not know what a "ref" is and move the "hooks" comment to the end.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
Show changes to Documentation/git-push.adoc +7 −6
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index d1978650d6..25d972f248 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -19,12 +19,9 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Updates remote refs using local refs, while sending objects
-necessary to complete the given refs.
-
-You can make interesting things happen to a repository
-every time you push into it, by setting up 'hooks' there.  See
-documentation for linkgit:git-receive-pack[1].
+Updates one or more branches, tags, or other references in a remote
+repository from your local repository, and sends all necessary data
+that isn't already on the remote.
 
 When the command line does not specify where to push with the
 `<repository>` argument, `branch.*.remote` configuration for the
@@ -44,6 +41,10 @@ corresponding upstream branch, but as a safety measure, the push is
 aborted if the upstream branch does not have the same name as the
 local one.
 
+You can make interesting things happen to a repository
+every time you push into it, by setting up 'hooks' there.  See
+documentation for linkgit:git-receive-pack[1].
+
 
 OPTIONS[[OPTIONS]]
 ------------------
-- 
gitgitgadget
Julia Evans via GitGitGadget· Oct 6, 2025, 18:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v5 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

From: Julia Evans <julia@jvns.ca>

From user feedback: one user mentioned that they don't know what the term "upstream branch" means. As far as I can tell, the most complete description is under the `--track` option in `git branch`. Upstreams are an important concept in Git and the `git branch` man page is not an obvious place for that information to live.

There's also a very terse description of "upstream branch" in the glossary that's missing a lot of key information, like the fact that the upstream is used by `git status` and `git pull`, as well as a description in `git-config` in `branch.<name>.remote` which doesn't explain the relationship to `git status` either.

Since the `git pull`, `git push`, and `git fetch` man pages already include sections on REMOTES and the syntax for URLs, add a section on UPSTREAM BRANCHES to `urls-remotes.adoc`.

In the new UPSTREAM BRANCHES section, cover the various ways that upstreams branches are automatically set in Git, since users may mistakenly think that their branch does not have an upstream branch if they didn't explicitly set one.

A terminology note: Git uses two terms for this concept:
- "tracking" as in "the tracking information for the 'foo' branch"
  or the `--track` option to `git branch`
- "upstream" or "upstream branch", as in `git push --set-upstream`.
  This term is also used in the `git rebase` man page to refer to the
  first argument to `git rebase`, as well as in `git pull` to refer to
  the branch which is going to be merged into the current branch ("merge
  the upstream branch into the current branch")

Use "upstream branch" as a heading for this concept even though the term "upstream branch" is not always used strictly in the sense of "the tracking information for the current branch". "Upstream" is used much more often than "tracking" in the Git docs to refer to this concept and the goal is to help users understand the docs.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/urls-remotes.adoc | 42 +++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)
Show changes to Documentation/urls-remotes.adoc +42 −0
diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes.adoc
index 9b10151198..57b1646d3e 100644
--- a/Documentation/urls-remotes.adoc
+++ b/Documentation/urls-remotes.adoc
@@ -92,5 +92,47 @@ git push uses:
 ------------
 
 
+[[UPSTREAM-BRANCHES]]
+UPSTREAM BRANCHES
+-----------------
+
+Branches in Git can optionally have an upstream remote branch.
+Git defaults to using the upstream branch for remote operations, for example:
+
+* It's the default for `git pull` or `git fetch` with no arguments.
+* It's the default for `git push` with no arguments, with some exceptions.
+  For example, you can use the `branch.<name>.pushRemote` option to push
+  to a different remote than you pull from, and by default with
+  `push.default=simple` the upstream branch you configure must have
+  the same name.
+* Various commands, including `git checkout` and `git status`, will
+  show you how many commits have been added to your current branch and
+  the upstream since you forked from it, for example "Your branch and
+  'origin/main' have diverged, and have 2 and 3 different commits each
+  respectively".
+
+The upstream is stored in `.git/config`, in the "remote" and "merge"
+fields. For example, if `main`'s upstream is `origin/main`:
 
+------------
+[branch "main"]
+   remote = origin
+   merge = refs/heads/main
+------------
 
+You can set an upstream branch explicitly with
+`git push --set-upstream <remote> <branch>`
+but Git will often automatically set the upstream for you, for example:
+
+* When you clone a repository, Git will automatically set the upstream
+  for the default branch.
+* If you have the `push.autoSetupRemote` configuration option set,
+  `git push` will automatically set the upstream the first time you push
+  a branch.
+* Checking out a remote-tracking branch with `git checkout <branch>`
+  will automatically create a local branch with that name and set
+  the upstream to the remote branch.
+
+[NOTE]
+Upstream branches are sometimes referred to as "tracking information",
+as in "set the branch's tracking information".
-- 
gitgitgadget
Kristoffer Haugsbakk· Oct 7, 2025, 12:23 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v5 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Mon, Oct 6, 2025, at 20:58, Julia Evans via GitGitGadget wrote:
Show 7 quoted lines
>[snip]
>
> There's also a very terse description of "upstream branch" in the
> glossary that's missing a lot of key information, like the fact that the
> upstream is used by `git status` and `git pull`, as well as a
> description in `git-config` in `branch.<name>.remote` which doesn't
> explain the relationship to `git status` either.
nit: s/either/, either/ ?

I think that would flow better given the long distance between the last punctuation/comma and the end of the sentence.

Show 7 quoted lines
>
> Since the `git pull`, `git push`, and `git fetch` man pages already
> include sections on REMOTES and the syntax for URLs, add a section on
> UPSTREAM BRANCHES to `urls-remotes.adoc`.
>
> In the new UPSTREAM BRANCHES section, cover the various ways that
> upstreams branches are automatically set in Git, since users may
nit: s/upstreams branches/upstream branches/
> mistakenly think that their branch does not have an upstream branch if
> they didn't explicitly set one.
>
>[snip]
Julia Evans· Oct 7, 2025, 13:35 UTC · re: Kristoffer Haugsbakk · lore

Re: [PATCH v5 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Tue, Oct 7, 2025, at 8:23 AM, Kristoffer Haugsbakk wrote:
Show 13 quoted lines
> On Mon, Oct 6, 2025, at 20:58, Julia Evans via GitGitGadget wrote:
>>[snip]
>>
>> There's also a very terse description of "upstream branch" in the
>> glossary that's missing a lot of key information, like the fact that the
>> upstream is used by `git status` and `git pull`, as well as a
>> description in `git-config` in `branch.<name>.remote` which doesn't
>> explain the relationship to `git status` either.
>
> nit: s/either/, either/ ?
>
> I think that would flow better given the long distance between the last
> punctuation/comma and the end of the sentence.

Is it the norm in this project to provide detailed copy editing feedback on commit messages like this? Of course it's important for commit messages to be accurate and to explain the motivation behind the changes, but I'm surprised by the attention to commas.

Show 9 quoted lines
>>
>> Since the `git pull`, `git push`, and `git fetch` man pages already
>> include sections on REMOTES and the syntax for URLs, add a section on
>> UPSTREAM BRANCHES to `urls-remotes.adoc`.
>>
>> In the new UPSTREAM BRANCHES section, cover the various ways that
>> upstreams branches are automatically set in Git, since users may
>
> nit: s/upstreams branches/upstream branches/

Will fix this typo if there's anything else to address (or if folks think that this is worth a re-roll on its own, not sure what the norms are).

D. Ben Knoble· Oct 7, 2025, 18:35 UTC · re: Julia Evans · lore

Re: [PATCH v5 2/5] doc: add an UPSTREAM BRANCHES section to pull/push/fetch

On Tue, Oct 7, 2025 at 9:35 AM Julia Evans <julia@jvns.ca> wrote:
Show 20 quoted lines
>
> On Tue, Oct 7, 2025, at 8:23 AM, Kristoffer Haugsbakk wrote:
> > On Mon, Oct 6, 2025, at 20:58, Julia Evans via GitGitGadget wrote:
> >>[snip]
> >>
> >> There's also a very terse description of "upstream branch" in the
> >> glossary that's missing a lot of key information, like the fact that the
> >> upstream is used by `git status` and `git pull`, as well as a
> >> description in `git-config` in `branch.<name>.remote` which doesn't
> >> explain the relationship to `git status` either.
> >
> > nit: s/either/, either/ ?
> >
> > I think that would flow better given the long distance between the last
> > punctuation/comma and the end of the sentence.
>
> Is it the norm in this project to provide detailed copy editing feedback
> on commit messages like this? Of course it's important for commit
> messages to be accurate and to explain the motivation behind the
> changes, but I'm surprised by the attention to commas.

AFAIK, yes, though I can see how it might appear discouraging to irregular contributors.

Show 13 quoted lines
>
> >>
> >> Since the `git pull`, `git push`, and `git fetch` man pages already
> >> include sections on REMOTES and the syntax for URLs, add a section on
> >> UPSTREAM BRANCHES to `urls-remotes.adoc`.
> >>
> >> In the new UPSTREAM BRANCHES section, cover the various ways that
> >> upstreams branches are automatically set in Git, since users may
> >
> > nit: s/upstreams branches/upstream branches/
>
> Will fix this typo if there's anything else to address (or if folks think that this
> is worth a re-roll on its own, not sure what the norms are).

It usually ends up depending on whether Junio applies the typo-fixes locally, I think. If there's nothing else and Junio grabs these, then we probably don't need another re-roll.

-- 
D. Ben Knoble
Julia Evans via GitGitGadget· Oct 6, 2025, 18:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v5 3/5] doc: git-push: clarify "where to push"

From: Julia Evans <julia@jvns.ca>

It's not obvious that "`branch.*.remote` configuration"` refers to the upstream, so say "upstream" instead.

The sentence is also quite hard to parse right now, use "defaults to" to simplify it.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
Show changes to Documentation/git-push.adoc +2 −4
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index 25d972f248..acdf25e5cd 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -23,10 +23,8 @@ Updates one or more branches, tags, or other references in a remote
 repository from your local repository, and sends all necessary data
 that isn't already on the remote.
 
-When the command line does not specify where to push with the
-`<repository>` argument, `branch.*.remote` configuration for the
-current branch is consulted to determine where to push.  If the
-configuration is missing, it defaults to 'origin'.
+The `<repository>` argument defaults to the upstream for the current branch,
+or `origin` if there's no configured upstream.
 
 When the command line does not specify what to push with `<refspec>...`
 arguments or `--all`, `--mirror`, `--tags` options, the command finds
-- 
gitgitgadget
Julia Evans via GitGitGadget· Oct 6, 2025, 18:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v5 4/5] doc: git-push: clarify "what to push"

From: Julia Evans <julia@jvns.ca>

From user feedback: 6 users says they found the "what to push" paragraphs confusing, for many different reasons, including:

* what does "..." in <refspec>... mean?
* "consult XXX configuration" is hard to parse
* it refers to the `git-config` man page even though the config
  information for `git push` is included in this man page under
  CONFIGURATION
* the default ("push to a branch with the same name") is what they use
  99% of the time, they would have expected it to appear earlier instead
  of at the very end
* not understanding what the term "upstream" means in Git
  ("are branches tracked by some system besides their names?"")

Also, the current explanation of `push.default=simple` ("the current branch is pushed to the corresponding upstream branch, but as a safety measure, the push is aborted if the upstream branch does not have the same name as the local one.") is not accurate: `push.default=simple` does not always require you to set a corresponding upstream branch.

Address all of these by
* using a numbered "in order of precedence" list
* giving a more accurate explanation of how `push.default=simple` works
* giving a little bit of context around "upstream branch": it's
  something that you may have to set explicitly
* referring to the new UPSTREAM BRANCHES section

The default behaviour is still discussed pretty late but it should be easier to skim now to get to the relevant information.

In "`git push` may fail if...", I'm intentionally being vague about what exactly `git push` does, because (as discussed on the mailing list) the behaviour of `push.default=simple` is very confusing, perhaps broken, and certainly not worth trying to explain in an introductory context. `push.default.simple` sometimes requires you to set an upstream and sometimes doesn't and the exact conditions under which it does/doesn't are hard to describe.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)
Show changes to Documentation/git-push.adoc +15 −12
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index acdf25e5cd..aa01efcc0a 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -26,18 +26,20 @@ that isn't already on the remote.
 The `<repository>` argument defaults to the upstream for the current branch,
 or `origin` if there's no configured upstream.
 
-When the command line does not specify what to push with `<refspec>...`
-arguments or `--all`, `--mirror`, `--tags` options, the command finds
-the default `<refspec>` by consulting `remote.*.push` configuration,
-and if it is not found, honors `push.default` configuration to decide
-what to push (See linkgit:git-config[1] for the meaning of `push.default`).
-
-When neither the command-line nor the configuration specifies what to
-push, the default behavior is used, which corresponds to the `simple`
-value for `push.default`: the current branch is pushed to the
-corresponding upstream branch, but as a safety measure, the push is
-aborted if the upstream branch does not have the same name as the
-local one.
+To decide which branches, tags, or other refs to push, Git uses
+(in order of precedence):
+
+1. The `<refspec>` argument(s) (for example `main` in `git push origin main`)
+   or the `--all`, `--mirror`, or `--tags` options
+2. The `remote.*.push` configuration for the repository being pushed to
+3. The `push.default` configuration. The default is `push.default=simple`,
+   which will push to a branch with the same name as the current branch.
+   See the <<CONFIGURATION,CONFIGURATION>> section below for more on `push.default`.
+
+`git push` may fail if you haven't set an upstream for the current branch,
+depending on what `push.default` is set to.
+See the <<UPSTREAM-BRANCHES,UPSTREAM BRANCHES>> section below for more
+on how to set and use upstreams.
 
 You can make interesting things happen to a repository
 every time you push into it, by setting up 'hooks' there.  See
@@ -696,6 +698,7 @@ a `git gc` command on the origin repository.
 
 include::transfer-data-leaks.adoc[]
 
+[[CONFIGURATION]]
 CONFIGURATION
 -------------
 
-- 
gitgitgadget
Julia Evans via GitGitGadget· Oct 6, 2025, 18:58 UTC · re: Julia Evans via GitGitGadget · lore

[PATCH v5 5/5] doc: git-push: Add explanation of `git push origin main`

From: Julia Evans <julia@jvns.ca>

What happens if you run `git push` without any arguments is actually extremely complex to explain, as discussed in the previous commit.

But it's very easy to explain what `git push <remote> <branch>` does, so start the man page by explaining what that does.

The hope is that someone could just stop reading the man page here and never learn anything else about `git push`, and that would be fine.

Signed-off-by: Julia Evans <julia@jvns.ca>
---
 Documentation/git-push.adoc | 4 ++++
 1 file changed, 4 insertions(+)
Show changes to Documentation/git-push.adoc +4 −0
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
index aa01efcc0a..36bf1cc438 100644
--- a/Documentation/git-push.adoc
+++ b/Documentation/git-push.adoc
@@ -23,6 +23,10 @@ Updates one or more branches, tags, or other references in a remote
 repository from your local repository, and sends all necessary data
 that isn't already on the remote.
 
+The simplest way to push is `git push <remote> <branch>`.
+`git push origin main` will push the local `main` branch to the `main`
+branch on the remote named `origin`.
+
 The `<repository>` argument defaults to the upstream for the current branch,
 or `origin` if there's no configured upstream.
 
-- 
gitgitgadget
D. Ben Knoble· Oct 6, 2025, 21:53 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v5 0/5] doc: git-push: clarify DESCRIPTION section

On Mon, Oct 6, 2025 at 2:58 PM Julia Evans via GitGitGadget <gitgitgadget@gmail.com> wrote:

Show 23 quoted lines
> changes in v5:
>
>  * remove a bad example of git branch --track, from Junio's review
>  * fix some formatting issues, from Jean-Noël's review
>
> Julia Evans (5):
>   doc: git-push: clarify intro
>   doc: add an UPSTREAM BRANCHES section to pull/push/fetch
>   doc: git-push: clarify "where to push"
>   doc: git-push: clarify "what to push"
>   doc: git-push: Add explanation of `git push origin main`
>
>  Documentation/git-push.adoc     | 46 +++++++++++++++++++--------------
>  Documentation/urls-remotes.adoc | 42 ++++++++++++++++++++++++++++++
>  2 files changed, 68 insertions(+), 20 deletions(-)
>
>
> base-commit: c44beea485f0f2feaf460e2ac87fdd5608d63cf0
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1964%2Fjvns%2Fclarify-push-v5
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1964/jvns/clarify-push-v5
> Pull-Request: https://github.com/gitgitgadget/git/pull/1964
>
> Range-diff vs v4:
No complaints from me, and range-diff looks good.
Thanks again!
Junio C Hamano· Oct 6, 2025, 22:07 UTC · re: Julia Evans via GitGitGadget · lore

Re: [PATCH v5 0/5] doc: git-push: clarify DESCRIPTION section

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 11 quoted lines
> I surveyed 16 Git users about the git push man page. Here's a rewrite of the
> DESCRIPTION section and the definition of <refspec> based on the feedback.
> The goal is to clarify it while communicating the same information. The most
> common piece of feedback was that folks didn't understand what the term
> "ref" means. Most of the users who said they did not understand the term
> "ref" have been using Git for 10+ years.
> ...
> changes in v5:
>
>  * remove a bad example of git branch --track, from Junio's review
>  * fix some formatting issues, from Jean-Noël's review
Thanks for working on this; I have no further comments to add.
Shall we mark the topic for 'next'?

← back to recent threads