8

Is it possible to do equivalent of git reset --hard --patch? (as this gives me: fatal: --patch is incompatible with --{hard,mixed,soft}).

In other words, how to do git reset --patch, but have the "unstaged" changes immediately discarded? (especially for newly added files - I don't want them littering my working directory, as I have it already quite littered with other stuff... so it's hard to find the new litter to remove it by hand...)

edit: or, maybe something like "multiple staging areas", where chunks can be passed from one to another easily like with --patch?

edit2: This seems not clear from the above question, so I'll copy a disclaimer from a comment I made below: Please note I don't want to have any files which show as "new file" in "Changes to be committed" in output of git status moved to "Untracked files". And for each of them I want to be able to explicitly decide if I want to keep them or discard them permanently (i.e. delete from disk).

In still other words: I'm trying to split a commit in two, but I have some "new files" in it. Some of them I want to move into the "other half" of the commit. But I don't want to have to add them one by one from the list of "Untracked files".

edit3: again to clarify: I have numerous "Untracked files" staying around that I don't want to add to .gitignore or .git/info/exclude for one or other reason.

akavel
  • 4,789
  • 1
  • 35
  • 66
  • Hmmm; I'm starting to think maybe `git stash --patch` can be my solution... somehow? not yet sure how exactly, however. – akavel Apr 18 '16 at 15:32
  • @user3159253 Split one commit into multiple commits, with high precision (thus --patch), not losing track of newly added files in process. – akavel Apr 18 '16 at 15:39
  • Err, to split a commit, you need `git reset` without `--hard`, no? – Matthieu Moy Apr 18 '16 at 15:41
  • Both of you, please note I explicitly stated (though in different words, so maybe unclear?) that *I don't want to have any files added in the commit moved to `Untracked files` in output of `git status`*. – akavel Apr 18 '16 at 15:43

5 Answers5

10

git reset --hard is meant to bring you to a clean state in essentially any situation: it works if you have staged or unstaged changes, if you have conflicts in your index, ... In these situations, a --patch option would not really make sense.

Actually, git reset --hard is usually not a good idea for the end-user: not only it discards changes, but does so in an unrecoverable way. As opposed to this, git stash keeps the changes. It can both be used for "I want to put these changes aside temporarily and I'll get them back soon" or "I know I want to discard these changes permanently, but I'll keep a backup just in case".

As you already noted, git stash has a --patch option, so it's clearly a good solution. An alternative is to use git reset --patch (without --hard) to get your index in the state you want, and then git stash --keep-index to have the work tree match the index.

If the change is large enough that you need to worry about the disk space usage, or if you just don't want to add clutter to your stash list, you can then run git stash drop to remove the stash entry.

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
Matthieu Moy
  • 15,151
  • 5
  • 38
  • 65
  • unfortunately, `git stash --patch` seems to skip any newly added files (i.e. ones which show as "new file" in "Changes to be committed"). I also tried `git stash --patch --keep-index`, but then this moves the newly added files back to untracked, which is again not what I want. – akavel Apr 18 '16 at 15:50
  • Updated my answer to include another solution with reset + stash -k. – Matthieu Moy Apr 18 '16 at 15:52
  • But then again, after `git reset -p`, if I had "new files" in staging area, and I unstage them, they'll become untracked, no? So `git stash` won't remove them from working dir, even with -k, no? – akavel Apr 18 '16 at 16:00
  • @akavel, wouldn't `git stash --patch -u` also save your untracked files? – kostix Apr 18 '16 at 17:04
  • @kostix as I mentioned in "edit3" in the Question, I do have some untracked files that I don't want to remove, and I don't want to add them to .gitignore either. – akavel Apr 18 '16 at 17:07
  • So, what do you want to do with these files? – Matthieu Moy Apr 18 '16 at 17:10
  • @MatthieuMoy I disagree, --hard is something to be careful of, but is useful when you have changes to definately discard. Which frequently i do. Adding it to the stash would be annoying, I don't want a bunch of junk sitting around in my stash. git reset hard --patch would allow you to easily discard changes from parts of files and such, and would allow you to know for sure what you're discarding. I think it makes perfect sense, functionally. – csga5000 Aug 11 '16 at 00:16
  • As I wrote, keeping stuff in your stash essentially eats a few kilobytes on your hard disk, it doesn't mean you have to use them one day. You probably didn't, but I bet you will one day erase important stuff with `git reset --hard`. I often see users saying "I know what I do, I don't need this safety", but much, much less frequently users who actually never needed any. Just like the old saying "there are two categories of Unix users: those who already did a mistake as root and those who will soon". Now, if *you* don't want this safety, it's your choice ;-). – Matthieu Moy Aug 12 '16 at 07:44
1

Found this question looking to do the same thing and discovered that six years later Git now has the restore command.

git restore -p -s HEAD did exactly what I wanted, letting me interactively reset parts of the working directory to HEAD.

It is still marked as experimental but looks like it was introduced at least as far back as 2019 https://stackoverflow.com/a/58003889 so should be fairly stable by now.

fizzyh2o
  • 1,237
  • 9
  • 18
0

I'm trying to split a commit in two, but I have some "new files" in it. Some of them I want to move into the "other half" of the commit. But I don't want to have to add them one by one from the list of "Untracked files".

now=`git write-tree`       # snapshot current state w/o bothering with a commit
git checkout --patch @     # undo whatever needs undoing
git commit                 # and that's the first commit
git read-tree -um $now     # now the original state's back in index and work tree
jthill
  • 55,082
  • 5
  • 77
  • 137
0

git reset -p undoes changes to index but leaves them in working tree. It is an antonym for git add -p.

If you want to unto changes in working tree you could selectively copy them to stash, review stash and finally delete stash:

git stash -p        # select hunks
git stash list -p   # review you don't shoot at foot, rollback with "git stash pop"
git stash drop      # forget the junk you wanted to remove
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
-1

I found a workaround: clone the repo to a temporary directory, and there I can git reset -p and git add . to edit the commits as I wish, not troubled by extra untracked files.

There are notable disadvantages however, including the fact that hooks are not cloned automatically. And any hardcoded paths won't work (including PATH, GOPATH, projects in IDE etc.)

akavel
  • 4,789
  • 1
  • 35
  • 66