Rhubbarb
Rhubbarb

Reputation: 4388

How do I edit an incorrect commit message in Git without including any staged modifications?

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:

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

Answers (4)

Rhubbarb
Rhubbarb

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

Nils Werner
Nils Werner

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

Mohammad AbuShady
Mohammad AbuShady

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

npcode
npcode

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

Related Questions