62

There's git add -p to stage changes and git checkout -p to discard changes interactively. How can I unstage changes from index by hunks?

(I thought that git unstage -p or git reset HEAD -p might work.)

LHM
  • 721
  • 12
  • 31
Dziamid
  • 11,225
  • 12
  • 69
  • 104

3 Answers3

80

If I am not mistaken, what you want is to unstage hunks interactively? I thought git reset -p does exactly that. Its prompt message is even exactly like Unstage this hunk?

Also from the manual:

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 git-add(1) to learn how to operate the --patch mode.

manojlds
  • 290,304
  • 63
  • 469
  • 417
  • It's a shame that i missed this bit in the docs. Sorry, guys. – Dziamid Sep 08 '11 at 09:03
  • 2
    @Dziamid There is no shame in that at all. I for one do not think it's obvious that reset should be the opposite of add, or even that they are pseudo-named stage/unstage. But luckily for me, you did the important task of asking the question! (allbeit a bit clumsy, since you seemed to already know the answer) kudos :D – Superole Dec 06 '13 at 15:34
  • This is the best thing I've ever found on stack overflow! Ok...well, at least, it scratches an itch I've been manually fixing by hand for a very long time. – Chris Pfohl Oct 16 '15 at 16:31
  • 4
    Good to know: The reverse direction makes the edit mode (e) a bit weird. All plus (+) lines will get unstaged. If you don't want to unstage, remove the plus - the documentation in the edit mode is not clear about this. This is somehow dangerous if you decide to cancel the operation while being in the editor and close it wihout saving - the result in unstaging the whole hunk – Daniel Alder Jul 22 '16 at 09:27
6

I found this answer very helpful when learning staging, so I thought I'd modify it for unstaging, as I haven't found a thorough answer on stackoverflow to this "How to git unstage one line or part of a file?" question.

As @manojlds says, you can use git reset --patch <filename> (or -p instead of --patch for short), and git will begin to break down your file into what it thinks are sensible "hunks" (portions of the file).

Git will then prompt you with a variant of this question:

Unstage this hunk [y,n,q,a,d,g,/,j,J,k,K,s,e,?]?

Here is a description of each option:

  • y unstage this hunk from the next commit
  • n stage this hunk for the next commit
  • q quit; do not unstage this hunk or any of the remaining hunks
  • a unstage this hunk and all later hunks in the file
  • d do not unstage this hunk or any of the later hunks in the file
  • g select a hunk to go to
  • / search for a hunk matching the given regex
  • j leave this hunk undecided, see next undecided hunk
  • J leave this hunk undecided, see next hunk
  • k leave this hunk undecided, see previous undecided hunk
  • K leave this hunk undecided, see previous hunk
  • s split the current hunk into smaller hunks
  • e manually edit the current hunk
  • ? print hunk help

NOTES ABOUT e MANUAL EDITING: Be extra careful when using the edit (e) mode above as it is not intuitive. I'll include and then revise the in-line git documentation:

# To remove '+' lines, make them ' ' lines (context).
# To remove '-' lines, delete them.                
# Lines starting with # will be removed. 

Revised for clarity:

  • All lines starting with + are lines currently staged to be added which will now be unstaged. To keep + lines from being unstaged (i.e. to leave them as staged changes), replace the initial + with a space character.
  • All lines starting with - are lines currently staged to be deleted which will now be unstaged. To keep - lines from being unstaged (i.e. to leave them as staged changes), delete each line entirely.
  • All lines with #, are comment lines and do not affect the content of the commit.
  • Perhaps also keep in mind @Daniel-Alder's comment, to avoid accidentally unstaging the whole hunk.

Afterwards, you can use:

  • git diff --staged to check that you unstaged/staged the correct changes
  • git add -p to stage mistakenly removed hunks
  • git commit -v to view your commit while you edit the commit message.

Reference for future: Git Tools - Interactive Staging

LHM
  • 721
  • 12
  • 31
-1

Since it hasn't been mentioned yet and hopefully isn't ridiculously obvious: use VScode.

  • From the single-page source control diff, highlight the section you want to unstage.
  • Select the 3 dots in the top right corner. There should be an Unstage Selected Ranges option.
  • Found it better than reset -p since you can control the chunk size, i.e. like for single lines.

Only tested on Mac. Current VScode 1.80.1

This currently works extremely well for me (Apologies for potential necro-posting)

Mote Zart
  • 861
  • 3
  • 17
  • 33