Dziamid
Dziamid

Reputation: 11599

Git interactive unstage part of a file or by hunks

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.)

Upvotes: 64

Views: 9936

Answers (3)

LHM
LHM

Reputation: 889

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 prevent + 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 prevent - 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

Upvotes: 7

Mote Zart
Mote Zart

Reputation: 960

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)

Upvotes: 0

manojlds
manojlds

Reputation: 301587

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.

Upvotes: 82

Related Questions