Reputation: 282
Say I’ve been staging changes using git add
, but then realize that there is some small change—consisting of a single hunk, let’s say—I should commit separately before committing the staged changes. If this change is in an unstaged file path
, all I need to do is git commit path
. If however it is in a file which contains changes which are already staged, I intuitively thought something like git commit -po
would allow me to interactively select changes to commit, while also ignoring staged changes, but instead I get the following:
$ git commit -po
fatal: Only one of --include/--only/--all/--interactive/--patch can be used.
Is there a relatively simple shortcut which allows me to achieve what I want, without having for example to commit the staged changes to a temporary branch and then merge?
Upvotes: 3
Views: 95
Reputation: 60487
There's only three usual places to store content for a path: the work tree, the index entry, and the committed tree. git commit -o
applies the work tree content to a new commit.
You need a fourth set of content for the path: the committed content but with selected changes from your work tree, and Git's --patch
options are set up to produce their partial staging in the index entry, but Git's --only
option is set up for whole-file slices from the work tree, so easiest is to save and reset the index, do git commit -p
, then restore the index.
Brute-force method using git's content-tracker core commands git write-tree
and git read-tree
to save and restore the index:
index=`git write-tree` # save the current index
git reset -q # reset it to clean checkout
git commit -p $thatpath # commit -p with just that path
git read-tree $index # restore the index
edit after getting a night's sleep: use a sideband index file. This will preserve inflight merge conflicts or git add -n
s in the current index that can't be committed as-is.
temp=$(git rev-parse --git-dir)/scratchindex
GIT_INDEX_FILE=$temp git reset -q
GIT_INDEX_FILE=$temp git commit -p $thatpath
Upvotes: 2
Reputation: 52081
You can do the following sequence of actions:
git commit
(create the "complete" commit)git reset HEAD~
(move back one step)git add -p ...; git commit
(create the small commit)git restore -S -s <sha> -- .
where <sha>
is the commit you created at step 1 (you may find it in git reflog
)Also worth mentioning: you can use the standard git gui
tool (comes distributed with git) to do step 2 and 3 with a GUI (even step 1 actually).
You would tick the "amend commit" checkbox which appears to the right, below the file view and over the "commit message" text area, and you can then:
The GUI is stock Tcl/Tk and looks a bit clunky, but I came to find it really useful for reviewing and editing the changes I want to commit.
Upvotes: 1
Reputation: 282
Not ideal but does exactly what is wanted:
git commit -p
small change (along with already staged changes)git stash
git reset HEAD^
git commit -p
small changegit add -u
git stash pop
We end up where we started, with the same material staged and unstaged, except the small change is committed.
Upvotes: 0
Reputation: 7130
You could use git restore
combined with the --staged
and --patch
options to selectively unstage the hunks of changes that have been added to the index by mistake.
git restore --staged --patch <file>
After that, you could stage the remaining changes and record them with a separate commit as you intended.
Upvotes: 1