wodow
wodow

Reputation: 4345

How to edit the last git commit as a patch file?

Sometimes it is useful to modify a commit by editing a patch file rather than by changing files directly, adding them to the working set and then amending a commit.

To make this easy, it would be useful to have a command in git that opens the most recent commit in $EDITOR as a patch file, in the same way that issuing git commit --amend (without any changes staged) immediately allows editing of the commit message in an editor.

Is this possible in git

  1. as a single command
  2. without losing the commit message?

Upvotes: 10

Views: 4349

Answers (2)

In case you need more than one commit edited, you can use git format-patch git am

git format-patch ${commit_hash}^ --stdout > patch
# edit the patch file accordingly
git reset --hard ${commit_hash}^
git am < patch

Upvotes: 0

Chris Maes
Chris Maes

Reputation: 37812

I'm not sure if it is possible in a single command, but almost:

git reset -N HEAD~
git add --edit
git commit --reuse-message=ORIG_HEAD

some explanations:

  • git reset -N HEAD~ : destroy last commit but keep the changes
  • git add --edit allows you to edit your changes in patch format
  • git commit --reuse-message=ORIG_HEAD : commit your staged changes with the commit message from ORIG_HEAD which is the pointer to the commit you made before git reset.

NOTE: since only git add --edit needs for interaction, you could even just chain the commands on one line and create a bash or git alias for it if desired:

git reset -N HEAD~ && git add --edit && git commit --reuse-message=ORIG_HEAD

NOTE2 if you edit your commit, some changes will remain in your git repository after this command. You must choose to throw them all away (git checkout -- :/) or commit them or...

If you don't do anything with these changes; then calling the above commands twice will always show you the changes from your very first commit:

git commit -am "very first commit"
git reset -N HEAD~
git add --edit # edit very first commit as patch
git commit --reuse-message=ORIG_HEAD
# you now have some unstaged changes lying around.
git reset HEAD~ # undo second commit
# the unstaged changes that are lying around now 
# are a combination of second commit and the unstaged changes
# that were still lying around.
# That combination = content of very first commit
git add --edit # edit that combination
git commit --reuse-message=ORIG_HEAD

If you would like a full command that you can continue applying; you could include the throwing away of changes:

git reset -N HEAD~ && git add --edit && git commit --reuse-message=ORIG_HEAD && git checkout -- :/

Note that this is dangerous because you might be throwing away changes...


full-blown script

you might save this script as /usr/bin/git-edit-last-commit, then you can run it as git edit-last-commit:

#!/bin/bash
set -e # exit on first error
if ! git diff-files --quiet
then
    echo "Your git repository is not clean: you have unstaged changes."
    exit 1
fi
if ! git diff-index --quiet --cached HEAD --
then
    echo "Your git repository is not clean: you have staged changes."
    exit 1
fi
git reset -N HEAD~
git add --edit
git commit --reuse-message=ORIG_HEAD
# supposing that this edit is really what you wanted, we can throw away leftovers
# if work was lost, in can be recovered using git reflog
git checkout -- :/

Upvotes: 10

Related Questions