git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Why not git reset --hard <path>?

From
GSGeorge Spelvin <linux@horizon.com>
Date
Sep 29, 2015, 16:15 UTC
Message-ID
<20150929161543.23444.qmail@ns.horizon.com>
In-Reply-To
<xmqqvbaub5s4.fsf@gitster.mtv.corp.google.com>
Show 11 quoted lines
> I agree with you if we limit the scope to "reset --hard" that does
> not mention any commit on the command line (or says "HEAD").
> 
> However, for things like:
>
>     $ git reset --hard HEAD^ Makefile
>     $ git reset --hard HEAD@{4.hours.ago} Makefile
>
> I do not think "reset --hard" is a good match.  Conceptually, you
> are grabbing what was stored in a given commit and checking that out
> to your current workspace (that is, the index and the working tree).

I actually disagree, BUT that was based on an inaccurate mental model, so I'm not sure if my judgement can be trusted. Still, I'll blather on just to give a different perspective.

To me, "git reset --hard" is "git reset" plus checking out from the index to the working directory. That's the difference and the only difference.

So any difference in behaviour between
	git reset --hard <revision> -- <paths>
and
	git reset --mixed <revision> -- <paths>
	git checkout -- <paths>
needs to be justified.  (There might be some if a file does not exist in
the revision.)
Show 7 quoted lines
> All modes of "git reset" are primarily about updating where in the
> history DAG your HEAD points at, and then adjusting your current
> workspace to that update, taking into account the reason why you are
> repointing your HEAD in the history DAG (e.g. when doing --hard
> reset, you want the workspace to match what the commit your HEAD now
> points at; when doing --soft reset, you don't want any changes
> done).

Er... no. Re-pointing HEAD can *only* be done as a global operation. That's the single most fundamental difference between git and CVS.

Any time you specify a path, *obviously* that part can't be done, so git-reset just skips that part and goes on to the index-updating part..

Git reset also skips that part in the single most common invocation scenario: un-doing git-add. That's for a different reason (pointing HEAD to HEAD is a no-op), but it contributes to the mental model that git-reset is fundamentally used for copying from history to the index.

That's my mental model, for what little it's worth (given the caveat above):
- git checkout is fundamentally about copying from the index to the
  working directory.  If can also move HEAD first (and create branches!)
  as a convenience feature.
- git reset is fundamentally about copying from HEAD to the index.
  Like git-checkout, it can also move HEAD first (and copy to the working
  directory) as a convenience feature.

To me, "git reset" is "throw the changes away and get me back to some previous state". That's why it's the tool I reached for in the merge-conflict situation that started this thread.

I didn't think to try "git checkout" because I needed to overwrite the merge conflict in the index, and I don't think of "git checkout" as doing that. (Globally, it fails if there are unresolved conflits.)

Previous: Jacob KellerNext: Philip Oakley
Message 7 of 11 in “Why not git reset --hard <path>?”
  1. George SpelvinSep 28, 2015
  2. Junio C HamanoSep 28, 2015
  3. Jacob KellerSep 28, 2015
  4. Junio C HamanoSep 28, 2015
  5. Theodore Ts'oSep 28, 2015
  6. Jacob KellerSep 29, 2015
  7. George SpelvinSep 29, 2015
  8. Philip OakleySep 29, 2015
  9. George SpelvinSep 28, 2015
  10. Junio C HamanoSep 28, 2015
  11. George SpelvinSep 28, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.