* Why not git reset --hard <path>?
@ 2015-09-28 20:34 George Spelvin
2015-09-28 20:42 ` Junio C Hamano
0 siblings, 1 reply; 11+ messages in thread
From: George Spelvin @ 2015-09-28 20:34 UTC (permalink / raw)
To: git; +Cc: linux
I was applying an old forgotten stash to see if there were any edits in
it I wanted to preserve, and my old changes to one file made no sense
any more. I wanted to drop then all and keep the version in HEAD.
I'd been using git reset <path> after resolving conflicts, to leave
the changes in the same un-staged state they were before the stash,
so I tried using "git reset --hard crypto/842.c" to throw away
my local changes.
And I got
fatal: Cannot do hard reset with paths.
So I did "git reset <path>" followed by "git checkout <path>", which
achieved what I wanted.
But what I don't understand is why git reset couldn't do it for me in one
step.
I understand that "git reset --soft" makes no sense with a path, but
why not --hard?
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 20:34 Why not git reset --hard <path>? George Spelvin
@ 2015-09-28 20:42 ` Junio C Hamano
2015-09-28 20:53 ` Jacob Keller
2015-09-28 22:36 ` George Spelvin
0 siblings, 2 replies; 11+ messages in thread
From: Junio C Hamano @ 2015-09-28 20:42 UTC (permalink / raw)
To: George Spelvin; +Cc: git
"George Spelvin" <linux@horizon.com> writes:
> I was applying an old forgotten stash to see if there were any edits in
> it I wanted to preserve, and my old changes to one file made no sense
> any more. I wanted to drop then all and keep the version in HEAD.
>
> I'd been using git reset <path> after resolving conflicts, to leave
> the changes in the same un-staged state they were before the stash,
> so I tried using "git reset --hard crypto/842.c" to throw away
> my local changes.
>
> And I got
> fatal: Cannot do hard reset with paths.
>
> So I did "git reset <path>" followed by "git checkout <path>", which
> achieved what I wanted.
>
> But what I don't understand is why git reset couldn't do it for me in one
> step.
>
> I understand that "git reset --soft" makes no sense with a path, but
> why not --hard?
I do not think there is anything fundamentally wrong for wishing for
"reset --hard <pathspec>". It probably is just that nobody needed
it, because "git checkout HEAD <pathspec>" is a 99% acceptable
substitute for it (the only case where it makes a difference is when
you added a path to the index that did not exist in HEAD).
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 20:42 ` Junio C Hamano
@ 2015-09-28 20:53 ` Jacob Keller
2015-09-28 21:19 ` Junio C Hamano
2015-09-29 19:40 ` Philip Oakley
2015-09-28 22:36 ` George Spelvin
1 sibling, 2 replies; 11+ messages in thread
From: Jacob Keller @ 2015-09-28 20:53 UTC (permalink / raw)
To: Junio C Hamano; +Cc: George Spelvin, Git List
On Mon, Sep 28, 2015 at 1:42 PM, Junio C Hamano <gitster@pobox.com> wrote:
> "George Spelvin" <linux@horizon.com> writes:
>> I understand that "git reset --soft" makes no sense with a path, but
>> why not --hard?
>
> I do not think there is anything fundamentally wrong for wishing for
> "reset --hard <pathspec>". It probably is just that nobody needed
> it, because "git checkout HEAD <pathspec>" is a 99% acceptable
> substitute for it (the only case where it makes a difference is when
> you added a path to the index that did not exist in HEAD).
>
Personally, I would like to see this simply given the number of times
that I use git reset --hard <path> and then realize I should have used
git checkout instead. I conceptually think reset --hard should do
that, and that checkout is really not meant to do that as a concept.
I may have some time to try and give this a look in the next few days...
Regards,
Jake
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 20:53 ` Jacob Keller
@ 2015-09-28 21:19 ` Junio C Hamano
2015-09-28 21:36 ` Theodore Ts'o
` (2 more replies)
2015-09-29 19:40 ` Philip Oakley
1 sibling, 3 replies; 11+ messages in thread
From: Junio C Hamano @ 2015-09-28 21:19 UTC (permalink / raw)
To: Jacob Keller; +Cc: George Spelvin, Git List
Jacob Keller <jacob.keller@gmail.com> writes:
> On Mon, Sep 28, 2015 at 1:42 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> "George Spelvin" <linux@horizon.com> writes:
>>> I understand that "git reset --soft" makes no sense with a path, but
>>> why not --hard?
>>
>> I do not think there is anything fundamentally wrong for wishing for
>> "reset --hard <pathspec>". It probably is just that nobody needed
>> it, because "git checkout HEAD <pathspec>" is a 99% acceptable
>> substitute for it (the only case where it makes a difference is when
>> you added a path to the index that did not exist in HEAD).
>
> Personally, I would like to see this simply given the number of times
> that I use git reset --hard <path> and then realize I should have used
> git checkout instead. I conceptually think reset --hard should do
> that, and that checkout is really not meant to do that as a concept.
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).
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).
It is only when you use "git reset" to update your HEAD to point at
the exact same commit when interaction with <pathspec> could make
sense, but conceptually the use case is covered better by
"checkout", which does _not_ futz with the history at all. The
command is primarily about preparing your workspace (that is, the
index and the working tree) toward the work you do to prepare for
the next commit you are going to make. Either you check out a
branch so that your next commit goes to that branch (and you take
your local changes with you when you do so), or you grab contents
from other existing commits to prepare for your work.
So while I am OK with loosening "reset --hard" with <pathspec> if
the command weren't given any commit from the command line, I doubt
that would be a real improvement.
I suspect it may even hurt the users by placing them in a wrong
mental model (i.e. I doubt you would wish "reset --hard <path>" to
work if your starting point were "reset is primarily about moving in
the history DAG and adjust the workspace accordingly").
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 21:19 ` Junio C Hamano
@ 2015-09-28 21:36 ` Theodore Ts'o
2015-09-29 7:06 ` Jacob Keller
2015-09-29 16:15 ` George Spelvin
2 siblings, 0 replies; 11+ messages in thread
From: Theodore Ts'o @ 2015-09-28 21:36 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jacob Keller, George Spelvin, Git List
I personally have in my .gitconfig:
[alias]
revert-file = checkout HEAD --
I'm not sure revert-file is the best name, but it's what I've used
because I've been contaminated by the concept/naming of "p4 revert",
which I do use a fair amount to undo local edits for one or more files
when I've been forced to use perforce or perforce-like systems. Given
that it confuses the concept of how "git revert" works, maybe
something like "git unedit <pathspec>" would work better.
Given though it's so easy to address this with a single line in a
user's .gitconfig, I guess the question is whether it's worthwhile to
make a change that would be visible to all users, and perhaps more
importantly, all new users to git.
- Ted
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 20:42 ` Junio C Hamano
2015-09-28 20:53 ` Jacob Keller
@ 2015-09-28 22:36 ` George Spelvin
2015-09-28 22:58 ` Junio C Hamano
1 sibling, 1 reply; 11+ messages in thread
From: George Spelvin @ 2015-09-28 22:36 UTC (permalink / raw)
To: gitster, linux; +Cc: git, jacob.keller, tytso
Junio C Hamano <gitster@pobox.com> wrote:
> "git checkout HEAD <pathspec>" is a 99% acceptable substitute for it
> (the only case where it makes a difference is when you added a path to
> the index that did not exist in HEAD).
Er, wait a minute...
"git checkout <tree-ish> <pathspec>" modifies the index?
Damn, I've been using git for years and I never knew that.
I thought it only modified the working tree.
But I just tested, and it does. Damn, now I have to figure out
how to "leapfrog" a file from history into the working tree without
overwriting the index; that's occasionally useful.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 22:36 ` George Spelvin
@ 2015-09-28 22:58 ` Junio C Hamano
2015-09-28 23:52 ` George Spelvin
0 siblings, 1 reply; 11+ messages in thread
From: Junio C Hamano @ 2015-09-28 22:58 UTC (permalink / raw)
To: George Spelvin; +Cc: git, jacob.keller, tytso
"George Spelvin" <linux@horizon.com> writes:
> Junio C Hamano <gitster@pobox.com> wrote:
>> "git checkout HEAD <pathspec>" is a 99% acceptable substitute for it
>> (the only case where it makes a difference is when you added a path to
>> the index that did not exist in HEAD).
>
> Er, wait a minute...
>
> "git checkout <tree-ish> <pathspec>" modifies the index?
>
> Damn, I've been using git for years and I never knew that.
... which would be an indication that the behaviour is most likely
the most natural one.
> But I just tested, and it does. Damn, now I have to figure out
> how to "leapfrog" a file from history into the working tree without
> overwriting the index; that's occasionally useful.
... and indeed it is useful in some rare cases. Either
git diff <tree-ish> <pathspec> | git apply -R
or
git checkout <tree-ish> <pathspec> &&
git reset <pathspec>
are what I would use, and as an old-timer, the former is what I do.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 22:58 ` Junio C Hamano
@ 2015-09-28 23:52 ` George Spelvin
0 siblings, 0 replies; 11+ messages in thread
From: George Spelvin @ 2015-09-28 23:52 UTC (permalink / raw)
To: gitster, linux; +Cc: git, jacob.keller, tytso
Junio C Hamano <gitster@pobox.com> wrote:
> "George Spelvin" <linux@horizon.com> writes:
>> "git checkout <tree-ish> <pathspec>" modifies the index?
>>
>> Damn, I've been using git for years and I never knew that.
>
> ... which would be an indication that the behaviour is most likely
> the most natural one.
I think it's more that often, staging a file to the index
is pretty harmless, so it doesn't actually matter.
Both of the commonest forms of commit ("git commit -a" and "git commit
[-o] <paths>") aren't affected, and if I'm doing something trickier,
I'll usually examine the status and make sure I've got it right.
So I could have encountered it and put it down to fat-fingering on
my part.
>> But I just tested, and it does. Damn, now I have to figure out
>> how to "leapfrog" a file from history into the working tree without
>> overwriting the index; that's occasionally useful.
> ... and indeed it is useful in some rare cases. Either
>
> git diff <tree-ish> <pathspec> | git apply -R
>
> or
>
> git checkout <tree-ish> <pathspec> &&
> git reset <pathspec>
The former would work, and thanks for the idea, but for a single file
I'd probably do one of
git show <tree-ish>:<path> > <path>
git cat-file blob <tree-ish>:<path> > <path>
The checkout/reset wouldn't work in the case I'm thinking about, which
is when I want to import a small piece (say, helper function that got
deleted) from an old or other-branch version of a file. I.e. a partial
revert or cherry-pick.
If I had some current changes to merge with, I'd stage them, pull the
*other* version into the tree, and use something like git-gui to add the
hunk I want to the staged version.
The whole point is that the staged state is important and I don't
want it overwritten.
There are other ways, of course:
- Show or cat-file the other version into a temporary file and manually
copy and paste. No need to stage anything.
- Commit the current change, then add the additional changes and amend the
commit.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 21:19 ` Junio C Hamano
2015-09-28 21:36 ` Theodore Ts'o
@ 2015-09-29 7:06 ` Jacob Keller
2015-09-29 16:15 ` George Spelvin
2 siblings, 0 replies; 11+ messages in thread
From: Jacob Keller @ 2015-09-29 7:06 UTC (permalink / raw)
To: Junio C Hamano; +Cc: George Spelvin, Git List
On Mon, Sep 28, 2015 at 2:19 PM, Junio C Hamano <gitster@pobox.com> wrote:
> 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).
>
Agreed. I just get used to thinking about using it against HEAD. it's
just weird to me that something which sometimes switches branches is
also the thing to grab a version of a file.
reset hard really would be weird in this case, because you really
don't know if the user meant "rewind the history, but keep everything
*except* that listed file..
That makes sense now that I think about it. Thanks.
Regards,
Jake
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 21:19 ` Junio C Hamano
2015-09-28 21:36 ` Theodore Ts'o
2015-09-29 7:06 ` Jacob Keller
@ 2015-09-29 16:15 ` George Spelvin
2 siblings, 0 replies; 11+ messages in thread
From: George Spelvin @ 2015-09-29 16:15 UTC (permalink / raw)
To: gitster, jacob.keller; +Cc: git, linux
> 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.)
> 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.)
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Why not git reset --hard <path>?
2015-09-28 20:53 ` Jacob Keller
2015-09-28 21:19 ` Junio C Hamano
@ 2015-09-29 19:40 ` Philip Oakley
1 sibling, 0 replies; 11+ messages in thread
From: Philip Oakley @ 2015-09-29 19:40 UTC (permalink / raw)
To: Jacob Keller, Junio C Hamano; +Cc: George Spelvin, Git List
From: "Jacob Keller" <jacob.keller@gmail.com>
> On Mon, Sep 28, 2015 at 1:42 PM, Junio C Hamano <gitster@pobox.com> wrote:
>> "George Spelvin" <linux@horizon.com> writes:
>>> I understand that "git reset --soft" makes no sense with a path, but
>>> why not --hard?
>>
>> I do not think there is anything fundamentally wrong for wishing for
>> "reset --hard <pathspec>". It probably is just that nobody needed
>> it, because "git checkout HEAD <pathspec>" is a 99% acceptable
>> substitute for it (the only case where it makes a difference is when
>> you added a path to the index that did not exist in HEAD).
>>
>
> Personally, I would like to see this simply given the number of times
> that I use git reset --hard <path> and then realize I should have used
> git checkout instead. I conceptually think reset --hard should do
> that, and that checkout is really not meant to do that as a concept.
>
> I may have some time to try and give this a look in the next few days...
>
> Regards,
> Jake
> --
I also recently had this problem of expecting to be able to use something
like `git reset --hard -- <path>` to clear up some crud and having to cast
around for the right approach.
Would it at least be worth flagging up the alternate ` git checkout --
path` a little better within the 'get reset' man pages? At the moment its
hidden at the end of the git reset [-q] [<tree-ish>] [--] <paths>… section,
so is easily missed.
(i.e. should I flesh out a patch, or would the nuances bury it...?)
Philip
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2015-09-29 19:40 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-28 20:34 Why not git reset --hard <path>? George Spelvin
2015-09-28 20:42 ` Junio C Hamano
2015-09-28 20:53 ` Jacob Keller
2015-09-28 21:19 ` Junio C Hamano
2015-09-28 21:36 ` Theodore Ts'o
2015-09-29 7:06 ` Jacob Keller
2015-09-29 16:15 ` George Spelvin
2015-09-29 19:40 ` Philip Oakley
2015-09-28 22:36 ` George Spelvin
2015-09-28 22:58 ` Junio C Hamano
2015-09-28 23:52 ` George Spelvin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).