-
Notifications
You must be signed in to change notification settings - Fork 156
doc: git-push: clarify DESCRIPTION section #1964
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
30a8f63
to
7211413
Compare
/submit |
Submitted as [email protected] To fetch this version into
To fetch this version to local tag
|
Error: 7211413 was already submitted |
operation. This parameter can be either a URL | ||
(see the section <<URLS,GIT URLS>> below) or the name | ||
of a remote (see the section <<REMOTES,REMOTES>> below). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans via GitGitGadget" <[email protected]> writes:
> From: Julia Evans <[email protected]>
>
> - 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 <[email protected]>
> ---
> 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.
> +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?
> + 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.
> + 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?
> + 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
>> +`:<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`.
>> +`+` 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 `+`.
>> +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.
> 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.
>> + 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
Documentation/git-push.adoc
Outdated
documentation for linkgit:git-receive-pack[1]. | ||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans via GitGitGadget" <[email protected]> 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`).
> +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.
> 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....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
> 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
|
||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans via GitGitGadget" <[email protected]> writes:
> From: Julia Evans <[email protected]>
>
> Signed-off-by: Julia Evans <[email protected]>
>
> 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 <[email protected]>
There is some funny ordering problem with the commit log body and
sign-off.
> ---
> 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
[--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]] | ||
[--no-verify] [<repository> [<refspec>...]] | ||
|
||
DESCRIPTION |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "D. Ben Knoble" wrote (reply to this):
On Tue, Aug 26, 2025 at 4:40 PM Julia Evans via GitGitGadget
<[email protected]> wrote:
>
> From: Julia Evans <[email protected]>
>
> - Users don't understand what a "ref" is, expand it
[snip]
> 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
>
> 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"D. Ben Knoble" <[email protected]> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "D. Ben Knoble" wrote (reply to this):
+cc Junio due to his reply to my reply
On Thu, Aug 28, 2025 at 1:48 PM Julia Evans <[email protected]> wrote:
>
> > 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Kristoffer Haugsbakk" wrote (reply to this):
On Thu, Aug 28, 2025, at 18:18, Junio C Hamano wrote:
> "D. Ben Knoble" <[email protected]> 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
User |
Documentation/git-push.adoc
Outdated
documentation for linkgit:git-receive-pack[1]. | ||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "D. Ben Knoble" wrote (reply to this):
On Tue, Aug 26, 2025 at 4:40 PM Julia Evans via GitGitGadget
<[email protected]> wrote:
>
> From: Julia Evans <[email protected]>
>
> - 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")
?
> - 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 <[email protected]>
> ---
> 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
operation. This parameter can be either a URL | ||
(see the section <<URLS,GIT URLS>> below) or the name | ||
of a remote (see the section <<REMOTES,REMOTES>> below). | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "D. Ben Knoble" wrote (reply to this):
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
<[email protected]> wrote:
>
> From: Julia Evans <[email protected]>
>
> - 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!
> 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.
> +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.
> + 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 "^"
> + 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.)
> + 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.
> +
> ++
> +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.
> (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
User |
There are issues in commit af6ee52: |
1 similar comment
There are issues in commit af6ee52: |
There are issues in commit 5b4cf34: |
There are issues in commit 5a9901d: |
There are issues in commit d0dff98: |
There are issues in commit c868126: |
There are issues in commit 1c8e16b: |
79bb21c
to
59732f1
Compare
/submit |
Submitted as [email protected] To fetch this version into
To fetch this version to local tag
|
[--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]] | ||
[--no-verify] [<repository> [<refspec>...]] | ||
|
||
DESCRIPTION |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans via GitGitGadget" <[email protected]> writes:
> From: Julia Evans <[email protected]>
>
> 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.
> -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?
> @@ -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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
> 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.
>> -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.
>> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans" <[email protected]> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
>> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Ben Knoble wrote (reply to this):
> Le 16 sept. 2025 à 14:46, Julia Evans <[email protected]> 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 »?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
Ben Knoble <[email protected]> writes:
>> Le 16 sept. 2025 à 14:46, Julia Evans <[email protected]> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
Junio C Hamano <[email protected]> writes:
> "Julia Evans" <[email protected]> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
> 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
include::pull-fetch-param.adoc[] | ||
|
||
--stdin:: | ||
Read refspecs, one per line, from stdin in addition to those provided |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans via GitGitGadget" <[email protected]> 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 ;-).
> 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.
> +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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
On Fri, Sep 12, 2025, at 5:17 PM, Junio C Hamano wrote:
> "Julia Evans via GitGitGadget" <[email protected]> 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.
>> +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.
> 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! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans" <[email protected]> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
On Mon, Sep 15, 2025, at 5:48 PM, Junio C Hamano wrote:
> "Julia Evans" <[email protected]> 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.
> 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.
|
||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans via GitGitGadget" <[email protected]> writes:
> -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.
|
||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans via GitGitGadget" <[email protected]> writes:
> From: Julia Evans <[email protected]>
>
> 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
>> 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.
This branch is now known as |
This patch series was integrated into seen via git@67ab24a. |
include::pull-fetch-param.adoc[] | ||
|
||
--stdin:: | ||
Read refspecs, one per line, from stdin in addition to those provided |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Julia Evans via GitGitGadget" <[email protected]> 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
> 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
Junio C Hamano <[email protected]> writes:
>> +```
>> +[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.
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`,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
Junio C Hamano <[email protected]> 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`,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, "Julia Evans" wrote (reply to this):
On Tue, Sep 16, 2025, at 1:39 AM, Junio C Hamano wrote:
> Junio C Hamano <[email protected]> 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.
This patch series was integrated into seen via git@705fffe. |
This patch series was integrated into seen via git@60597c4. |
There was a status update in the "Cooking" section about the branch Doc updates. Expecting a reroll. cf. <[email protected]> source: <[email protected]> |
This patch series was integrated into seen via git@330d0d9. |
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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:
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.changes in v3:
git push
also needs to send data in addition to updating the branch, from Junio's reviewpushRemote
andgit 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 reviewcc: "D. Ben Knoble" [email protected]
cc: "Kristoffer Haugsbakk" [email protected]