Reputation: 4388
If I have staged some changes, and in the process notice an error in my previous (and un-pushed) commit message, is there a way to amend the commit without folding in my staged changes?
I see various options on the man page for git-commit
that perform a related function, but no combination that seems to produce exactly the desired effect:
--amend
--all
(automatically stage), but no '--none
'--message
--only
(only the specified paths)--
<no-more-options>...The option --only
with an empty file list (which I don't know how to specify), would almost be right, but that might in any case remove changes from the last commit (which I don't want).
The naïve method is to reset
and then commit --amend
, but that requires repeating the staging work. Alternatively, I could commit my staged changes, and edit the no-longer-latest commit message via a rebase
, but that seems a to be awkward and overkill for just editing a message.
I don't think stash save
can help either, as stash
does not seem able to preserve the distinction between staged and unstaged changes. (Unless it's possible to stash
only what has been staged? Again, I don't see how to do that.)
This question is related to How to modify existing, unpushed commits? where there's plenty of useful information amongst the answers, but this, slightly different question is not addressed.
Any hints gratefully received; thanks.
Upvotes: 1
Views: 135
Reputation: 4388
I wanted to put this as a comment to @npcode's answer, but couldn't get the formatting right. What follows is heavily based on that answer...
Here's a finer-grained explanation, and one that allows the original commit message to be edited:
(1) $ git cat-file -p HEAD | grep "^tree\b" | awk '{print $2}'
prints the root tree id of HEAD ${tree-id}
, needed in step (4)
Optionally:
(2) $ git log -1 --format="%B" > ci.txt
dumps the old commit message in ci.txt
, which can then be edited. Optionally and alternatively, and entirely new commit message file could be written.
(3) $ edit
ci.txt
Then either
(4a) $ git commit-tree ${tree-id} -F ci.txt -p HEAD^
or
(4b) $ git commit-tree ${tree-id} -m "<new message>" -p HEAD^
to create a new commit object with commit message, respectively, from a file or directly on the command line.
Either of these commands
prints the id ${commit-id}
of the new commit, needed in step (5)
(5) $ git reset --soft ${commit-id}
to set the new commit as the current HEAD.
@npcode and @Daniel combine steps (1), (4b) and (5).
Upvotes: 1
Reputation: 36719
You can just continue with your work and do an interactive rebase afterwards:
git rebase -i
in the list of commits you see replace pick
with reword
for all commits you want to reword.
Upvotes: 0
Reputation: 42789
I think stashing should remember what was staged and what's not, maybe you need to use --no-keep-index
git stash --no-keep-index
Upvotes: 1
Reputation: 1390
You can do that with git-commit-tree
and git-reset
:
git reset --soft `git commit-tree <tree-id> -m "new message" -p HEAD^`
<tree-id>
is the root tree id of HEAD. You can get it by git cat-file -p HEAD
Upvotes: 2