See an alternative answer here: stackoverflow.com/a/18150592/520567 Your accepted answer is really an exact answer to your question but if you have your new commit ready before you decided to use edit, then this answer would be more straightforward. It can also work with multiple commits you want to merge/squash together with an older one.
– akostadinovAug 9 '13 at 15:45

13 Answers
13

You can use git rebase, for example, if you want to modify back to commit bbc643cd, run

$ git rebase --interactive 'bbc643cd^'

In the default editor, modify pick to edit in the line whose commit you want to modify. Make your changes and then commit them with the same message you had before:

$ git commit --all --amend --no-edit

to modify the commit, and after that

$ git rebase --continue

to return back to the previous head commit.

WARNING: Note that this will change the SHA-1 of that commit as well as all children -- in other words, this rewrites the history from that point forward. You can break repos doing this if you push using the command git push --force

Another interesting option within this flow is once you have moved to the commit you want to modify, instead of modifying files and ammed over the commit on top (the one you're editing), you may want to split that commit into two different commits (or even more). In that case, move back to the commit to edit, and run "git reset HEAD^". that will put the modified files of that commit into the stage. Now pick and commit any files as you wish. This flow is quite well explained in "git-rebase" man page. See section "Splitting commits". bit.ly/d50w1M
– Diego PinoMar 15 '10 at 19:18

193

In Git 1.6.6 and newer you can use the reword action in git rebase -i instead of edit (it automatically opens the editor and continues with the rest of the rebase steps; this obviates the use of git commit --ammend and git rebase --continue when you only need to change the commit message and not the content).
– Chris JohnsenNov 29 '10 at 3:35

12

After running 'git rebase hash^ --interactive', then marking edit on the commit, 'git commit --amend' just shows the commit message - not the actual code. How can I change the code that was committed? Thanks!
– mikemaccanaAug 15 '12 at 8:47

97

It's worth noting that you may need to run git stash before git rebase and git stash pop afterwards, if you have pending changes.
– user123444555621Sep 18 '13 at 8:42

7

Note that with newer git, it would be wiser to follow prompt instructions instead of blindly using git commit --all --amend --no-edit here. All I had to do after git rebase -i ... was to git commit --amend normally then git rebase --continue.
– Eric ChenMar 2 '17 at 9:04

* Watch out for options like --hard and --force though — they can discard data.
* Also, don't rewrite history on any branches you're collaborating on.

On many systems, git rebase -i will open up Vim by default. Vim doesn't work like most modern text editors, so take a look at how to rebase using Vim. If you'd rather use a different editor, change it with git config --global core.editor your-favorite-text-editor.

The middle of your answer is a weird place to put what I can only describe as a miniture advertisement for VIM. It's irrelevant to the question and just clutters up your answer.
– IntentssMay 29 '15 at 14:29

17

@Intentss: Ah, I can see why that looked weird. The reasoning behind it was that Vim is the default text editor on many systems, so many people's first experience of interactive rebasing is a screen where typing makes the cursor fly around all over the place. Then, they switch their editor to something else, and their second experience of interactive rebasing is fairly normal, but leaves them wondering why it uses a text file instead of a GUI. To achieve flow with rebasing, you need something like Vim, or Emacs' rebase-mode.
– ZazMay 30 '15 at 23:59

1

If I had to use something like Gedit or nano to interactive rebase, I would rebase a lot less. Maybe that wouldn't be such a bad thing, as I am a bit of a rebase addict.
– ZazMay 31 '15 at 0:00

6

Okay. Seeing as so many people find that part irrelevant, I've condensed it down to 3 lines and also explained how to change the editor if need be.
– ZazOct 7 '15 at 16:38

11

Awesome! I did not know you could use @ as shorthand for HEAD. Thanks for posting this.
– James KoOct 2 '16 at 20:42

Interactive rebase with --autosquash is something I frequently use when I need to fixup previous commits deeper in the history. It essentially speeds up the process that ZelluX's answer illustrates, and is especially handy when you have more than one commit you need to edit.

From the documentation:

--autosquash

When the commit log message begins with "squash! …​" (or "fixup! …​"), and there is a commit whose title begins with the same …​, automatically modify the todo list of rebase -i so that the commit marked for squashing comes right after the commit to be modified

You can also use git commit --fixup=@~ instead of git commit -m "fixup! Commit2". This is especially useful when your commit messages are longer and it would be a pain to type out the whole thing.
– ZazOct 19 '15 at 20:57

each ^ indicates how many commits back you want to edit, if it's only one (the commit hash that you specified), then you just add one ^.

Using Vim you change the words pick to reword for the commits you want to change, save and quit(:wq). Then git will prompt you with each commit that you marked as reword so you can change the commit message.

Each commit message you have to save and quit(:wq) to go to the next commit message

If you want to exit without applying the changes, press :q!

EDIT: to navigate in vim you use j to go up, k to go down, h to go left, and l to go right( all this in NORMAL mode, press ESC to go to NORMAL mode ).
To edit a text, press i so that you enter the INSERT mode, where you insert text.
Press ESC to go back to NORMAL mode :)

What git push --force does is overwrite the remotes commits with your local commits. That's not the case of this topic :)
– betoharresJul 14 '16 at 17:12

@BetuUuUu of course if your commits are pushed to remote and you have modified commit message locally, you would want to force push to remote, isn't it?
– Sudip BhandariJul 5 '17 at 9:03

@SudipBhandari That's the feeling I get. I didn't force, and now I have an extra branch, mirroring all the commits back to the one whose message I changed, which is super-ugly.
– ruffinFeb 5 '18 at 16:35

If for some reason you don't like interactive editors, you can use git rebase --onto.

Say you want to modify Commit1. First, branch from beforeCommit1:

git checkout -b amending [commit before Commit1]

Second, grab Commit1 with cherry-pick:

git cherry-pick Commit1

Now, amend your changes, creating Commit1':

git add ...
git commit --amend -m "new message for Commit1"

And finally, after having stashed any other changes, transplant the rest of your commits up to master on top of your
new commit:

git rebase --onto amending Commit1 master

Read: "rebase, onto the branch amending, all commits between Commit1 (non-inclusive) and master (inclusive)". That is, Commit2 and Commit3, cutting the old Commit1 out entirely. You could just cherry-pick them, but this way is easier.

Isn't the point of the question to change the commit message? Because this answer doesn't address that, or at least not directly.
– wyttenDec 5 '18 at 18:10

@wytten the question doesn't ask about changing the commit message, it is about modifying the commit the is not HEAD. So an answer to your question would be "no, it's not the point of the question"
– DetharielDec 5 '18 at 19:50

after rearrange you need to replace ppick with f (fixup will merge without commit message) or s (squash merge with commit message can change in run time)

and then save your tree.

now merge done with existing commit.

Note: Its not preferable method unless you're maintain on your own. if
you have big team size its not a acceptable method to rewrite git
tree will end up in conflicts which you know other wont. if you want
to maintain you tree clean with less commits can try this and if its
small team otherwise its not preferable.....

For me it was for removing some credentials from a repo.
I tried rebasing and ran into a ton of seemingly unrelated conflicts along the way when trying to rebase --continue.
Don't bother attempting to rebase yourself, use the tool called BFG (brew install bfg) on mac.

Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).