-
Notifications
You must be signed in to change notification settings - Fork 157
doc: git-reset: clarify DESCRIPTION section #1991
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
From user feedback: three users commented that the `git reset [mode]`
form is the one that they primarily use, and that they were suprised to
see it listed last.
("I've never used git reset in any mode other than --hard").
Move it to be first, since the `git reset [mode]` form is what
"Reset current HEAD to the specified state" at the beginning refers
to, and because the `git reset [mode]` form is the only thing that
`git reset` uniquely does, the others could also be done with
`git restore`.
Signed-off-by: Julia Evans <[email protected]>
From user feedback, there were several points of confusion:
- What "tree-ish", "entries", "working tree", "HEAD", and "index" mean
("I have no clue what the index is", "I've been using git for 20 years
and still don't know what a tree-ish is"). Avoid using these terms
where it makes sense.
- What "optionally modifying index and working tree to match" means
("to match what?" "optionally based on what?")
Remove this from the intro, we can say it later when giving more
details.
- One user suggested that "The <tree-ish>/<commit> defaults to HEAD
in all forms." should be repeated later on, since it's easy to miss.
Instead say that HEAD is the default in each case later.
Another issue is that `git reset` consistently describes the action
it does as "Reset ...", commands should not use their name to describe
themselves, and that the word "mode" is used to mean several different
things on this page.
Address these by being more clear about two use cases for `git reset`
("to undo operations" and "to update staged files"), and explaining what
the conditions are for each case instead of forcing the user to figure
out the pattern is in first form vs the other 3 forms.
Signed-off-by: Julia Evans <[email protected]>
From user feedback, there was some confusion about the differences between the modes, including: 1. Sometimes it says "index" and sometimes "index file". Fix by replacing "index file" with "index". 2. Many comments about not being able to understand what `--merge` does. Fix by mentioning `git merge --abort` since my best guess is that most folks want to use that instead of `git reset --merge`. 3. Issues telling the difference between --soft and --mixed, as well as --keep. Leave --keep alone because I couldn't understand its use case, but change `--soft` / `--mixed` / `--hard` as follows: --mixed is the default, so put it first. Describe --soft/--mixed/--hard with the following structure: * Start by saying what happens to the files in the working directory, because the thing users want to avoid most is irretrievably losing changes to their working directory files. * Then describe what happens to the staging area. Right now it seems to frame leaving the index alone as being a sort of neutral action. I think this is part of what's confusing users, because in Git when you update HEAD, Git almost always updates the index to match HEAD. So leaving the index unchanged while updating HEAD is actually quite unusual, and it deserves to be flagged. * Finally, give an example for --soft to explain a common use case. Signed-off-by: Julia Evans <[email protected]>
From user feedback: - Continued confusion about the terms "tree-ish" and "pathspec" - The word "hunks" is confusing folks, use "changes" instead. - On the part about `git restore`, there were a few comments to the effect of "wait, this doesn't actually update any files? What? Why?" Be more direct that `git reset` does not update files: there's no obvious reason to suggest that folks use `git reset` followed by `git restore`, instead suggest just using `git restore`. Continue avoiding the use of the word "reset" to describe what "git reset" does. Signed-off-by: Julia Evans <[email protected]>
|
/submit |
|
Submitted as [email protected] To fetch this version into To fetch this version to local tag |
| ---- | ||
| git-reset - Reset current HEAD to the specified state | ||
|
|
||
| SYNOPSIS |
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/git-reset.adoc b/Documentation/git-reset.adoc
> index 3b9ba9aee9..9843682e81 100644
> --- a/Documentation/git-reset.adoc
> +++ b/Documentation/git-reset.adoc
> @@ -8,43 +8,17 @@ git-reset - Reset current HEAD to the specified state
> SYNOPSIS
> --------
> [synopsis]
> +git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
> git reset [-q] [<tree-ish>] [--] <pathspec>...
> git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
> git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
> -git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
>
> DESCRIPTION
> -----------
> -In the first three forms, copy entries from _<tree-ish>_ to the index.
> -In the last form, set the current branch head (`HEAD`) to _<commit>_,
> +In the first form, set the current branch head (`HEAD`) to _<commit>_,
> optionally modifying index and working tree to match.
> The _<tree-ish>_/_<commit>_ defaults to `HEAD` in all forms.
In the original, the "defaults to HEAD in all forms" did make sense,
but as the new text does not mention there are three other forms
like the original did, that sentence was made harder to fathom.
I can accept that you do not want to get ahead of yourself to
explain "copy from <treeish>" before you are ready to talk more
about these other forms, but we'd at least need to acknowledge that
what we want to refer to when we say "all forms" here. Perhaps
Among the four forms, the first form sets the current branch
head to .... In all forms, the tree-ish/commit defaults to
HEAD.
is easier to read?
> +In the last three forms, copy entries from _<tree-ish>_ to the index.
Or "The other three forms copy entries ..."?
Other than that, looks good to me.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, Oct 17, 2025, at 6:20 PM, Junio C Hamano wrote:
> "Julia Evans via GitGitGadget" <[email protected]> writes:
>
>> diff --git a/Documentation/git-reset.adoc b/Documentation/git-reset.adoc
>> index 3b9ba9aee9..9843682e81 100644
>> --- a/Documentation/git-reset.adoc
>> +++ b/Documentation/git-reset.adoc
>> @@ -8,43 +8,17 @@ git-reset - Reset current HEAD to the specified state
>> SYNOPSIS
>> --------
>> [synopsis]
>> +git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
>> git reset [-q] [<tree-ish>] [--] <pathspec>...
>> git reset [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
>> git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
>> -git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
>>
>> DESCRIPTION
>> -----------
>> -In the first three forms, copy entries from _<tree-ish>_ to the index.
>> -In the last form, set the current branch head (`HEAD`) to _<commit>_,
>> +In the first form, set the current branch head (`HEAD`) to _<commit>_,
>> optionally modifying index and working tree to match.
>> The _<tree-ish>_/_<commit>_ defaults to `HEAD` in all forms.
>
> In the original, the "defaults to HEAD in all forms" did make sense,
> but as the new text does not mention there are three other forms
> like the original did, that sentence was made harder to fathom.
That's true. I didn't pay very careful attention to the text here
because I completely rewrote it in a later patch anyway.
I'll make it say something that makes more sense.
> I can accept that you do not want to get ahead of yourself to
> explain "copy from <treeish>" before you are ready to talk more
> about these other forms, but we'd at least need to acknowledge that
> what we want to refer to when we say "all forms" here. Perhaps
>
> Among the four forms, the first form sets the current branch
> head to .... In all forms, the tree-ish/commit defaults to
> HEAD.
>
> is easier to read?
>
>> +In the last three forms, copy entries from _<tree-ish>_ to the index.
>
> Or "The other three forms copy entries ..."?
>
> Other than that, looks good to me.| @@ -1,50 +1,27 @@ | |||
| git-reset(1) | |||
| ============ | |||
|
|
|||
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, there were several points of confusion:
>
> - What "tree-ish", "entries", "working tree", "HEAD", and "index" mean
> ("I have no clue what the index is", "I've been using git for 20 years
> and still don't know what a tree-ish is"). Avoid using these terms
> where it makes sense.
> - What "optionally modifying index and working tree to match" means
> ("to match what?" "optionally based on what?")
> Remove this from the intro, we can say it later when giving more
> details.
> - One user suggested that "The <tree-ish>/<commit> defaults to HEAD
> in all forms." should be repeated later on, since it's easy to miss.
> Instead say that HEAD is the default in each case later.
>
> Another issue is that `git reset` consistently describes the action
> it does as "Reset ...", commands should not use their name to describe
> themselves, and that the word "mode" is used to mean several different
> things on this page.
>
> Address these by being more clear about two use cases for `git reset`
> ("to undo operations" and "to update staged files"), and explaining what
> the conditions are for each case instead of forcing the user to figure
> out the pattern is in first form vs the other 3 forms.
>
> Signed-off-by: Julia Evans <[email protected]>
> ---
> Documentation/git-reset.adoc | 13 ++++++++-----
> 1 file changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/git-reset.adoc b/Documentation/git-reset.adoc
> index 9843682e81..876187dc83 100644
> --- a/Documentation/git-reset.adoc
> +++ b/Documentation/git-reset.adoc
> @@ -3,7 +3,7 @@ git-reset(1)
>
> NAME
> ----
> -git-reset - Reset current HEAD to the specified state
> +git-reset - Set HEAD to point at the specified commit
The command has dual-purpose, and it is a bit disturbing that the
other one is not even mentioned in the original or in the updated
text. "The other three forms" is about resetting the index without
moving HEAD at all. Would this work better, I wonder?
Reset HEAD or index back to a known state
> +`git reset [<mode>] <commit>` changes which commit HEAD points to.
> +This makes it possible to undo various Git operations, for example
> +commit, merge, rebase, and pull.
Good. These are prime examples of when resetting to a known state
is useful.
> +However, when you specify files or directories or pass `--patch`,
> +`git reset` will instead update the staged version of the specified
> +files without updating HEAD.
I see no however here.
Other forms are not about flipping HEAD to any state we used to have
before. Instead, they are about populating index entries from the
state taken from an arbitrary tree-ish.
You can view them as enhanced variants of "git reset --mixed HEAD"
(read it as "unstage all changes"). They are enhanced in the sense
that unlike "git reset --mixed HEAD", the treeish the index entries
are taken from does not have to be HEAD, and also in the sense that
unlike "git reset --mixed HEAD", you can limit the index entries to
be affected to a subset of paths. I am not sure it would make it
easier to understand to explain them in terms of "reset --mixed HEAD"
but I am reasonably sure that it would appear confusing until a
reader realizes that the command has two very disinct mode, one that
is primarily about HEAD, the other that is primarily about index.
> `git reset [<mode>] [<commit>]`::
> This form resets the current branch head to _<commit>_ andThere 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, Oct 17, 2025, at 6:32 PM, Junio C Hamano wrote:
> "Julia Evans via GitGitGadget" <[email protected]> writes:
>
>> From: Julia Evans <[email protected]>
>>
>> From user feedback, there were several points of confusion:
>>
>> - What "tree-ish", "entries", "working tree", "HEAD", and "index" mean
>> ("I have no clue what the index is", "I've been using git for 20 years
>> and still don't know what a tree-ish is"). Avoid using these terms
>> where it makes sense.
>> - What "optionally modifying index and working tree to match" means
>> ("to match what?" "optionally based on what?")
>> Remove this from the intro, we can say it later when giving more
>> details.
>> - One user suggested that "The <tree-ish>/<commit> defaults to HEAD
>> in all forms." should be repeated later on, since it's easy to miss.
>> Instead say that HEAD is the default in each case later.
>>
>> Another issue is that `git reset` consistently describes the action
>> it does as "Reset ...", commands should not use their name to describe
>> themselves, and that the word "mode" is used to mean several different
>> things on this page.
>>
>> Address these by being more clear about two use cases for `git reset`
>> ("to undo operations" and "to update staged files"), and explaining what
>> the conditions are for each case instead of forcing the user to figure
>> out the pattern is in first form vs the other 3 forms.
>>
>> Signed-off-by: Julia Evans <[email protected]>
>> ---
>> Documentation/git-reset.adoc | 13 ++++++++-----
>> 1 file changed, 8 insertions(+), 5 deletions(-)
>>
>> diff --git a/Documentation/git-reset.adoc b/Documentation/git-reset.adoc
>> index 9843682e81..876187dc83 100644
>> --- a/Documentation/git-reset.adoc
>> +++ b/Documentation/git-reset.adoc
>> @@ -3,7 +3,7 @@ git-reset(1)
>>
>> NAME
>> ----
>> -git-reset - Reset current HEAD to the specified state
>> +git-reset - Set HEAD to point at the specified commit
>
> The command has dual-purpose, and it is a bit disturbing that the
> other one is not even mentioned in the original or in the updated
> text. "The other three forms" is about resetting the index without
> moving HEAD at all. Would this work better, I wonder?
>
> Reset HEAD or index back to a known state
That's true, though I think we should avoid using "Reset"
to explain what `git reset` does. Perhaps
Set HEAD or the index to a previous state
>> +`git reset [<mode>] <commit>` changes which commit HEAD points to.
>> +This makes it possible to undo various Git operations, for example
>> +commit, merge, rebase, and pull.
>
> Good. These are prime examples of when resetting to a known state
> is useful.
>
>> +However, when you specify files or directories or pass `--patch`,
>> +`git reset` will instead update the staged version of the specified
>> +files without updating HEAD.
>
> I see no however here.
>
> Other forms are not about flipping HEAD to any state we used to have
> before. Instead, they are about populating index entries from the
> state taken from an arbitrary tree-ish.
>
> You can view them as enhanced variants of "git reset --mixed HEAD"
> (read it as "unstage all changes"). They are enhanced in the sense
> that unlike "git reset --mixed HEAD", the treeish the index entries
> are taken from does not have to be HEAD, and also in the sense that
> unlike "git reset --mixed HEAD", you can limit the index entries to
> be affected to a subset of paths. I am not sure it would make it
> easier to understand to explain them in terms of "reset --mixed HEAD"
> but I am reasonably sure that it would appear confusing until a
> reader realizes that the command has two very disinct mode, one that
> is primarily about HEAD, the other that is primarily about index.
>
>> `git reset [<mode>] [<commit>]`::
>> This form resets the current branch head to _<commit>_ and
I agree that "git reset has two very distinct modes' is important.
Here's an idea for how to communicate that.
It doesn't fully capture all of the nuances of `git reset`'s command
line syntax, but maybe that's not the job of the intro sentence anyway.
I don't love the use of "things" in "two things" but it would be weird to
say "modes" because we already use "mode" to mean something else,
and I haven't thought of something better yet.
`git reset` does two things:
1. `git reset [<mode>] <commit>` changes which commit HEAD points to.
This makes it possible to undo various Git operations, for example
commit, merge, rebase, and pull.
2. When you specify files or directories or pass `--patch`, it updates
the staged version of the specified files.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:
>> Reset HEAD or index back to a known state
>
> That's true, though I think we should avoid using "Reset"
> to explain what `git reset` does. Perhaps
>
> Set HEAD or the index to a previous state
OK, though the state is not necessarily "previous".
> I agree that "git reset has two very distinct modes' is important.
> Here's an idea for how to communicate that.
> It doesn't fully capture all of the nuances of `git reset`'s command
> line syntax, but maybe that's not the job of the intro sentence anyway.
>
> I don't love the use of "things" in "two things" but it would be weird to
> say "modes" because we already use "mode" to mean something else,
> and I haven't thought of something better yet.
>
> `git reset` does two things:
I do not mind "things", as long as it is not mislead readers into
thinking that it may do two things at the same time. "modes" avoids
that problem, as "you use it one way, and it does one thing, and you
use it another way, and it does a very different thing" is the
natural implication of that word.
"The command can be used in two ways"? "can be used for two
different purposes?" I dunno.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 Mon, Oct 20, 2025 at 4:02 PM Junio C Hamano <[email protected]> wrote:
>
> "Julia Evans" <[email protected]> writes:
> > I agree that "git reset has two very distinct modes' is important.
> > Here's an idea for how to communicate that.
> > It doesn't fully capture all of the nuances of `git reset`'s command
> > line syntax, but maybe that's not the job of the intro sentence anyway.
> >
> > I don't love the use of "things" in "two things" but it would be weird to
> > say "modes" because we already use "mode" to mean something else,
> > and I haven't thought of something better yet.
> >
> > `git reset` does two things:
>
> I do not mind "things", as long as it is not mislead readers into
> thinking that it may do two things at the same time. "modes" avoids
> that problem, as "you use it one way, and it does one thing, and you
> use it another way, and it does a very different thing" is the
> natural implication of that word.
>
> "The command can be used in two ways"? "can be used for two
> different purposes?" I dunno.
Some options:
`git reset` does one of two different things
`git reset` can be used to accomplish either of the following:
--
D. Ben Knoble| according to the commit recorded in the superproject, also setting | ||
| the submodules' `HEAD` to be detached at that commit. | ||
| -- | ||
|
|
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:
> +`git reset` only modifies the index: use linkgit:git-restore[1] instead
> +if you'd like to also update the file in your working directory.
I cannot judge if it is clear enough with the above sentence that we
are only talking about "the other forms", but if that is the case
and it is clear we are not talking about the mode where the command
repoints HEAD to another commit, the above is a good piece of advice.
If not, perhaps
When specified what paths to modify, `git reset` updates only
the index (without updating the HEAD or working tree files). If
you want to update the files as well as the index entries, use
git-restore.
may be a way to clarify the distinction between two modes.
> `git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]`::
> - Interactively select hunks in the difference between the index
> - and _<tree-ish>_ (defaults to `HEAD`). The chosen hunks are applied
> - in reverse to the index.
> + Interactively select changes from the difference between the index
> + and the specified commit or tree (which defaults to `HEAD`).
> + The chosen changes are unstaged.
> +
> This means that `git reset -p` is the opposite of `git add -p`, i.e.
> -you can use it to selectively reset hunks. See the "Interactive Mode"
> -section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
> +you can use it to selectively unstage changes. See the "Interactive Mode"
> +section of linkgit:git-add[1] to learn how to use the `--patch` option.
I do not see a good reason why we avoid saying the noun "patch",
especially when we see it in the option. If we were allowed to say
"patch" here, "changes from the difference between ..." can be
rephrased to "parts of the patch that makes the index match the
specified commit", which may be simpler.
Also "unstaged" is only true when <tree-ish> is "HEAD". If you are
grabbing the contents recorded in a different commit and shoving
them into the index, that is not "unstaging" at all. Rather, if you
are planning to make a commit out of the index after doing so, that
is rather "staging" a change! While the verb "to (un)stage" may
have been a useful tool to explain the act of updating index entries
to describe its effect relative to what is in HEAD, in this
particular case, it is probably more confusing than illuninating to
use it.
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 17 oct. 2025 à 19:25, Junio C Hamano <[email protected]> a écrit :
>
> "Julia Evans via GitGitGadget" <[email protected]> writes:
>
>> `git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]`::
>> - Interactively select hunks in the difference between the index
>> - and _<tree-ish>_ (defaults to `HEAD`). The chosen hunks are applied
>> - in reverse to the index.
>> + Interactively select changes from the difference between the index
>> + and the specified commit or tree (which defaults to `HEAD`).
>> + The chosen changes are unstaged.
>> +
>> This means that `git reset -p` is the opposite of `git add -p`, i.e.
>> -you can use it to selectively reset hunks. See the "Interactive Mode"
>> -section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
>> +you can use it to selectively unstage changes. See the "Interactive Mode"
>> +section of linkgit:git-add[1] to learn how to use the `--patch` option.
>
> I do not see a good reason why we avoid saying the noun "patch",
> especially when we see it in the option. If we were allowed to say
> "patch" here, "changes from the difference between ..." can be
> rephrased to "parts of the patch that makes the index match the
> specified commit", which may be simpler.
I think the issue was the word « hunk », not « 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, Junio C Hamano wrote (reply to this):
Ben Knoble <[email protected]> writes:
>> Le 17 oct. 2025 à 19:25, Junio C Hamano <[email protected]> a écrit :
>>
>> "Julia Evans via GitGitGadget" <[email protected]> writes:
>>
>>> `git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]`::
>>> - Interactively select hunks in the difference between the index
>>> - and _<tree-ish>_ (defaults to `HEAD`). The chosen hunks are applied
>>> - in reverse to the index.
>>> + Interactively select changes from the difference between the index
>>> + and the specified commit or tree (which defaults to `HEAD`).
>>> + The chosen changes are unstaged.
>>> +
>>> This means that `git reset -p` is the opposite of `git add -p`, i.e.
>>> -you can use it to selectively reset hunks. See the "Interactive Mode"
>>> -section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
>>> +you can use it to selectively unstage changes. See the "Interactive Mode"
>>> +section of linkgit:git-add[1] to learn how to use the `--patch` option.
>>
>> I do not see a good reason why we avoid saying the noun "patch",
>> especially when we see it in the option. If we were allowed to say
>> "patch" here, "changes from the difference between ..." can be
>> rephrased to "parts of the patch that makes the index match the
>> specified commit", which may be simpler.
>
> I think the issue was the word « hunk », not « patch ».
I know. That is exactly where my question comes from.| section of linkgit:git-add[1] to learn how to operate the `--patch` mode. | ||
| However, when you specify files or directories or pass `--patch`, | ||
| `git reset` will instead update the staged version of the specified | ||
| files without updating HEAD. |
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:
> +`--soft`::
> + Leaves your working directory unchanged. The index is left unchanged,
Why not "leave your working tree files and the index unchanged"?
> + so everything in your current commit will be staged.
Hmph, if a reader still has the "stage the changes" mental model,
then this would be true only when you are resetting to HEAD~1 (this
is one of the reasons why I am hesitant to overuse the verb
"stage"). If you are going to HEAD~5, such a reader would say that
the changes made by the past 5 commits are staged, not just the
commit you are on before resetting.
> + For example, if you have no staged changes, you can use
> + `git reset --soft HEAD~5; git commit`
> + to combine the last 5 commits into 1 commit.
Another thing that may be worth mentioning is that you can do this
even with local changes in the working tree, because you do not give
"-a" to the final "git commit".
> `--hard`::
> - Resets the index and working tree. Any changes to tracked files in the
> - working tree since _<commit>_ are discarded. Any untracked files or
> - directories in the way of writing any tracked files are simply deleted.
> + Overwrites all files and directories with the version from _<commit>_,
> + and may overwrite untracked files.
> + Updates the index to match the new HEAD, so nothing will be staged.
One thing that may be worth saying is that the paths in the working
tree that are tracked in the index that are not in <commit> will
disappear.
> `--merge`::
> + Mainly exists for backwards compatibility: `git merge --abort` is the
> + usual way to abort a merge. See linkgit:git-merge[1] for the differences.
There are operations that are not "git merge" that can leave the
index in an unmerged state, and you do not want to use "git merge
--abort" to get out of such a state, I would imagine. So I have a
feeling that we are better off without these two lines.
> Resets the index and updates the files in the working tree that are
> different between _<commit>_ and `HEAD`, but keeps those which are
> different between the index and working tree (i.e. which have changes
> which have not been added).
> If a file that is different between _<commit>_ and the index has
> unstaged changes, reset is aborted.
> -+
> -In other words, `--merge` does something like a `git read-tree -u -m <commit>`,
> -but carries forward unmerged index entries.
I do not mind losing this. Unlike the time back when these two
lines were written, nobody knows (and more importantly, nobody has
to know) what "read-tree -u -m" does, these days.
> `--keep`::
> Resets index entries and updates files in the working tree that are
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):
On Sat, Oct 18, 2025, at 12:53 AM, Junio C Hamano wrote:
> "Julia Evans via GitGitGadget" <[email protected]> writes:
>
>> +`--soft`::
>> + Leaves your working directory unchanged. The index is left unchanged,
>
> Why not "leave your working tree files and the index unchanged"?
The reason I say "working directory" instead of "working tree" is that
I've seen a few comments from users saying that they don't know
what "working tree" means. I'm still not sure what the reason for
calling it a "working tree" is.
The reason for keeping them separate sentences is just for symmetry with
the other commands, and also because (like I mentioned in the commit
message) "leaving X and Y unchanged" makes it sound like leaving X and
Y unchanged is a "neutral operation", while actually leaving the index
unchanged while updating HEAD is actually a fairly weird thing to do.
>> + so everything in your current commit will be staged.
>
> Hmph, if a reader still has the "stage the changes" mental model,
> then this would be true only when you are resetting to HEAD~1 (this
> is one of the reasons why I am hesitant to overuse the verb
> "stage"). If you are going to HEAD~5, such a reader would say that
> the changes made by the past 5 commits are staged, not just the
> commit you are on before resetting.
That's fair. I'll try to think about whether there's a better way to say
this.
Previously it said "This leaves all your changed files
"Changes to be committed", as git status would put it.", which has the
same issue ("changed files" since when exactly?).
Maybe I can fix this by being more explicit about which changes
exactly will show up as "staged" in `git status`.
>> + For example, if you have no staged changes, you can use
>> + `git reset --soft HEAD~5; git commit`
>> + to combine the last 5 commits into 1 commit.
>
> Another thing that may be worth mentioning is that you can do this
> even with local changes in the working tree, because you do not give
> "-a" to the final "git commit".
Maybe! I'm not sure if we want to encourage doing complex Git operations
with unstaged changes though. I feel like it often leads to suffering
and I think people who want to do that can already infer that it's
possible.
>> `--hard`::
>> - Resets the index and working tree. Any changes to tracked files in the
>> - working tree since _<commit>_ are discarded. Any untracked files or
>> - directories in the way of writing any tracked files are simply deleted.
>> + Overwrites all files and directories with the version from _<commit>_,
>> + and may overwrite untracked files.
>> + Updates the index to match the new HEAD, so nothing will be staged.
>
> One thing that may be worth saying is that the paths in the working
> tree that are tracked in the index that are not in <commit> will
> disappear.
Interesting, I don't think I knew that. Would this be a more accurate
description of what `git reset --hard` does, conceptually?
I want to make sure I understand how it works.
1. List every file that's either in the target commit or in the index
2. For each file, make it match the target commit
(overwriting untracked files if necessary)
>> `--merge`::
>> + Mainly exists for backwards compatibility: `git merge --abort` is the
>> + usual way to abort a merge. See linkgit:git-merge[1] for the differences.
>
> There are operations that are not "git merge" that can leave the
> index in an unmerged state, and you do not want to use "git merge
> --abort" to get out of such a state, I would imagine. So I have a
> feeling that we are better off without these two lines.
Do you mean `git reset` and `git cherry-pick`, or are there other operations
that can leave the operation in an unmerged state?
My mental model is that if there's a merge conflict, the best way to deal with it
is to use the appropriate `--abort` command (depending on how you got there),
because the command-specific `--abort` will know how to do things like
restore autostashed changes. But I agree that just saying "use `git merge --abort`
is not a complete description.
>> Resets the index and updates the files in the working tree that are
>> different between _<commit>_ and `HEAD`, but keeps those which are
>> different between the index and working tree (i.e. which have changes
>> which have not been added).
>> If a file that is different between _<commit>_ and the index has
>> unstaged changes, reset is aborted.
>> -+
>> -In other words, `--merge` does something like a `git read-tree -u -m <commit>`,
>> -but carries forward unmerged index entries.
>
> I do not mind losing this. Unlike the time back when these two
> lines were written, nobody knows (and more importantly, nobody has
> to know) what "read-tree -u -m" does, these days.
Thanks, it's useful for me to know more about the context at the time
this was written.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 Mon, Oct 20, 2025 at 4:28 PM Julia Evans <[email protected]> wrote:
>
> On Sat, Oct 18, 2025, at 12:53 AM, Junio C Hamano wrote:
> > "Julia Evans via GitGitGadget" <[email protected]> writes:
> >
> >> +`--soft`::
> >> + Leaves your working directory unchanged. The index is left unchanged,
> >
> > Why not "leave your working tree files and the index unchanged"?
>
> The reason I say "working directory" instead of "working tree" is that
> I've seen a few comments from users saying that they don't know
> what "working tree" means. I'm still not sure what the reason for
> calling it a "working tree" is.
At a guess: suppose I have a non-bare repository ~/code/git with
corresponding ~/code/git/.git directory, but PWD=~/code/git/t. Then my
working directory is "…/t" but my working tree includes all the stuff
Git is tracking above me, too! (It also helps draw parallelism with
git-worktree, but that's a bit circular.)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:
> On Sat, Oct 18, 2025, at 12:53 AM, Junio C Hamano wrote:
>> "Julia Evans via GitGitGadget" <[email protected]> writes:
>>
>>> +`--soft`::
>>> + Leaves your working directory unchanged. The index is left unchanged,
>>
>> Why not "leave your working tree files and the index unchanged"?
>
> The reason I say "working directory" instead of "working tree" is that
> I've seen a few comments from users saying that they don't know
> what "working tree" means. I'm still not sure what the reason for
> calling it a "working tree" is.
"working tree" refers to the directory that is the top level of a
checkout; I'd view (current) "working directory" can be anything
$(pwd), that may be outside control of any git repository, and that
is why I tend to avoid the latter when I want to be more precise
(and "worktree" is another thing---used to refer to one particular
"working tree" among other working trees attached to the same
repository).
But that distinction was not the part I wanted to comment on. The
question was about two sentences talking about two things
separately. IOW
Leave your working directory and the index unchanged.
is what I would have expected, and I was wondering why they are
treated separately. After all, the index is part of your working
tree state.
> The reason for keeping them separate sentences is just for symmetry with
> the other commands, and also because (like I mentioned in the commit
> message) "leaving X and Y unchanged" makes it sound like leaving X and
> Y unchanged is a "neutral operation", while actually leaving the index
> unchanged while updating HEAD is actually a fairly weird thing to do.
Sorry, but I do not understand this comment.
The index and the HEAD are two different things, and it is natural
that they can move independently. After all we update the former
without updating the latter all the time (it is called "git add").
Besides, the two things the --soft does not touch are the files in
the working tree and the index. The index has what you want to make
the next commit out of, and the working tree has the state that may
come after that state in the index. Keeping both of them intact
when moving HEAD around is one natural thing to do when you want to
squash the previous N commits after "git add <paths>" by doing "git
reset --soft HEAD~N && git commit". Contrasting to that, "--mixed"
would leave the files in the working tree intact, while matching the
index to the HEAD you are moving to, essentially undoing your "git
add"s before you decided to reset. That's another natural thing to
do when you decide to keep the clean slate and rebuild your index from
scratch to prepare for a commit that comes on top of the commit you
are moving to.
So, no, I do not understand the above comment.
> Do you mean `git reset` and `git cherry-pick`, or are there other operations
> that can leave the operation in an unmerged state?
There are many commands that leaves the index unmerged, like "am
-3", "rebase", "switch -m", "stash pop", etc.
|
User |
|
This patch series was integrated into seen via git@053832b. |
|
This branch is now known as |
|
This patch series was integrated into seen via git@37118eb. |
|
This patch series was integrated into seen via git@ee95231. |
|
There was a status update in the "Cooking" section about the branch Documentation updates. Comments? source: <[email protected]> |
|
This patch series was integrated into seen via git@7f6e03b. |
|
This patch series was integrated into seen via git@c083ed2. |
|
This patch series was integrated into seen via git@1fba770. |
|
There was a status update in the "Cooking" section about the branch Documentation updates. Expecting a reroll. cf. <[email protected]> source: <[email protected]> |
|
This patch series was integrated into seen via git@ea794e3. |
|
This patch series was integrated into seen via git@7a103ca. |
|
There was a status update in the "Cooking" section about the branch Documentation updates. Expecting a reroll. cf. <[email protected]> source: <[email protected]> |
|
This patch series was integrated into seen via git@63637e9. |
I got feedback from 24 Git users about the current
git resetman page, using this tool: https://text-feedback.wizardzines.com/git-reset.My main goals here are to highlight the
git reset [--soft | --hard | --mixed...] <commit>use ofgit resetthat many users commenting said they considered the "main" use (which is currently at the end), explain how--soft,--hardand--mixedwork more clearly, and to avoid using terminology that users don't understand when that's realistic.Like we discussed with
git checkout, there's some tension about using the word "index" since on one hand many users don't know what it means, but on the other hand (especially with commands likegit reset --hard) it gets very awkward to talk about what's going on precisely without using that word, since the index is a core concept in Git's data model. I've done my best here to use the word "index" where I think it's appropriate and use the word "staged" otherwise.There were also quite a few comments about the EXAMPLES section which I think could also be made clearer, but I'll defer that to a separate patch series to keep the size of this one under control.
cc: Ben Knoble [email protected]