How to modify a specified commit?

1,058,270

Solution 1

You can use git rebase. For example, if you want to modify commit bbc643cd, run

$ git rebase --interactive 'bbc643cd^'

Please note the caret ^ at the end of the command, because you need actually to rebase back to the commit before the one you wish to modify.

In the default editor, modify pick to edit in the line mentioning 'bbc643cd'.

Save the file and exit: git will interpret and automatically execute the commands in the file. You will find yourself in the previous situation in which you just had created commit bbc643cd.

At this point, bbc643cd is your last commit and you can easily amend it: make your changes and then commit them with the command:

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

After that, type:

$ 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

Solution 2

Use the awesome interactive rebase:

git rebase -i @~9   # Show the last 9 commits in a text editor

Find the commit you want, change pick to e (edit), and save and close the file. Git will rewind to that commit, allowing you to either:

  • use git commit --amend to make changes, or
  • use git reset @~ to discard the last commit, but not the changes to the files (i.e. take you to the point you were at when you'd edited the files, but hadn't committed yet).

The latter is useful for doing more complex stuff like splitting into multiple commits.

Then, run git rebase --continue, and Git will replay the subsequent changes on top of your modified commit. You may be asked to fix some merge conflicts.

Note: @ is shorthand for HEAD, and ~ is the commit before the specified commit.

Read more about rewriting history in the Git docs.


Don't be afraid to rebase

ProTip™:   Don't be afraid to experiment with "dangerous" commands that rewrite history* — Git doesn't delete your commits for 90 days by default; you can find them in the reflog:

$ git reset @~3   # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started

* 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.

Solution 3

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

Assume you have a history that looks like this:

$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1

and you have changes that you want to amend to Commit2 then commit your changes using

$ git commit -m "fixup! Commit2"

alternatively you can use the commit-sha instead of the commit message, so "fixup! e8adec4 or even just a prefix of the commit message.

Then initiate an interactive rebase on the commit before

$ git rebase e8adec4^ -i --autosquash

your editor will open with the commits already correctly ordered

pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3

all you need to do is save and exit

Solution 4

Run:

$ git rebase --interactive commit_hash^

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 :)

UPDATE: Here's a great link from github listing How to undo (almost) anything with git

Solution 5

Based on Documentation

Amending the message of older or multiple commit messages

git rebase -i HEAD~3 

The above displays a list of the last 3 commits on the current branch, change 3 to something else if you want more. The list will look similar to the following:

pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Replace pick with reword before each commit message you want to change. Let say you change the second commit in the list, your file will look like the following:

pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Save and close the commit list file, this will pop up a new editor for you to change your commit message, change the commit message and save.

Finally, force-push the amended commits.

git push --force
Share:
1,058,270
Sam Liao
Author by

Sam Liao

Developer focus solving problems.

Updated on July 08, 2022

Comments

  • Sam Liao
    Sam Liao almost 2 years

    I usually submit a list of commits for review. If I have the following commits:

    1. HEAD
    2. Commit3
    3. Commit2
    4. Commit1

    ...I know that I can modify head commit with git commit --amend. But how can I modify Commit1, given that it is not the HEAD commit?

  • Diego Pino
    Diego Pino about 14 years
    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
  • Chris Johnsen
    Chris Johnsen over 13 years
    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).
  • tripleee
    tripleee about 11 years
    Maybe I have an old version of Git, but mine (Git 1.5.6.5, on Debian 5, cough cough) required the --interactive option before the revision spec. I have edited the answer accordingly.
  • Ansel Halliburton
    Ansel Halliburton over 10 years
    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.
  • sstur
    sstur over 9 years
    Is there a shortucut command to edit a specific commit in the interactive rebase without opening the editor, finding the commit, marking it edit, then dropping back to the command line?
  • jpmc26
    jpmc26 about 9 years
    What are you rebasing to the parent (the bbc643cd^) of the commit you want to change, instead of the commit you actually want to change?
  • Zaz
    Zaz over 8 years
    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.
  • u01jmg3
    u01jmg3 almost 8 years
    Worked perfectly for me. Worth mentioning git push --force?
  • betoharres
    betoharres almost 8 years
    What git push --force does is overwrite the remotes commits with your local commits. That's not the case of this topic :)
  • Daniel Kobe
    Daniel Kobe over 7 years
    Should this be used on commits that have already been push to a remote branch?
  • Eric Chen
    Eric Chen about 7 years
    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.
  • Emmanuel Bourg
    Emmanuel Bourg almost 7 years
    I suggest adding the --preserve-merges option when rebasing, this will preserve the merge commits.
  • 18augst
    18augst almost 7 years
    git reset @~ exactly what I wanted to do after choosing commit with git rebase .... You're my hero)
  • Sudip Bhandari
    Sudip Bhandari almost 7 years
    @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?
  • Arin Taylor
    Arin Taylor almost 7 years
    you can use git checkout -b amending Commit1~1 to get the prior commit
  • tobymackenzie
    tobymackenzie over 6 years
    add --root and omit the ^ on the rebase command if editing the first commit, eg git rebase -i --root 'bbc643cd'. Via stackoverflow.com/a/14630424/1139122
  • tobymackenzie
    tobymackenzie over 6 years
    er, I guess just omit the hash entirely with --root
  • basickarl
    basickarl over 6 years
    @EricChen Could you not answer the question with a very easy to understand answer step by step. I think it would get a lot of attention.
  • basickarl
    basickarl over 6 years
    For people wanting to edit the first commit: git rebase -i --root.
  • Ariel Gabizon
    Ariel Gabizon over 6 years
    This didn't let me change the author of an old commit, which I need to do.
  • ruffin
    ruffin about 6 years
    @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.
  • Simon Feltman
    Simon Feltman about 6 years
    This works well. I added some extra functionality to do piecemeal fixups of a dirty tree for perfecting a commit set. `dirtydiff=$(git diff); if [ "${dirtydiff}" != "" ]; then echo "Stashing dirty tree" >&2; git stash; fi;
  • Dethariel
    Dethariel about 6 years
    One can also make amend-to handle unstaged files: git config --global alias.amend-to '!f() { SHA=git rev-parse "$1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
  • ms4720
    ms4720 about 6 years
    Git rebase --amend now has a reword keyword that only updates the commit messages, simpler and safer
  • Tomasz Kaczmarzyk
    Tomasz Kaczmarzyk about 6 years
    Interactive rebase might seem tricky at the beginning. I wrote a post (with pictures) which presents it in detail, step by step: blog.tratif.com/2018/04/19/the-power-of-git-interactive-reba‌​se
  • Dunatotatos
    Dunatotatos almost 6 years
    This is a nice solution if you do not want to make live-modification during an interactive rebase.
  • Francis Rodrigues
    Francis Rodrigues over 5 years
    If I use git rebase -i --root <commit-hash>, there is no possible to use git rebase --continue because it's not return back to the previous head commit
  • Erick Maynard
    Erick Maynard over 5 years
    I get the following error: error: There was a problem with the editor 'vi'. Please supply the message using either -m or -F option.
  • MrAn3
    MrAn3 over 5 years
    @MarcusJ I had to change the git editor to VS Code because I was not able to edit in the terminal one: you can find instructions on how to do that here: stackoverflow.com/questions/30024353/…
  • einpoklum
    einpoklum over 5 years
    do you actually need the single-quotes in the first command? I mean, can't you write bbc643cd^ instead of 'bbc643cd^' there?
  • OskarD90
    OskarD90 over 5 years
    This also rebased other branches that were ahead into the branch I was working on. Why?
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com over 5 years
    One concern with this method is that it could apply unrelated fixups.
  • wytten
    wytten over 5 years
    Isn't the point of the question to change the commit message? Because this answer doesn't address that, or at least not directly.
  • Dethariel
    Dethariel over 5 years
    @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"
  • user4674453
    user4674453 about 5 years
    I don't understand why it is so upped? This is merely answer how to modify only a comment of the commit but not the content.
  • Benjohn
    Benjohn almost 5 years
    This is really great – thanks. Following use of git reset @~ to make a few updates (mostly a git checkout file-i-didn't-mean-to-change), is there an easy way to put add that commit back with the original message? I copied the original message from the blurb output by git status, and then ran git rebase --continue, but I wondered if there is an easier way? Perhaps if there isn't an easier way, you could also mention this briefly in your answer?
  • Benjohn
    Benjohn almost 5 years
    Ah! I guess I could have used: git reset @~ -- file-i-didn't-mean-to-change followed by git commit --amend --no-edit?
  • ggb667
    ggb667 almost 5 years
    I'm confused, so how do we change the commit message?
  • greenhouse
    greenhouse almost 5 years
    @Tomasz Kaczmarzyk amazing article thank you! Just a quick question, what kind of results can be expected to see on team members locals (or when they do a git pull master) if you do a push —force?
  • Tomasz Kaczmarzyk
    Tomasz Kaczmarzyk almost 5 years
    @greenhouse if you modify and force-push, then other team members most probably will encounter merging conflicts. So you should be generally super-cautious about it. But if you modify something which nobody else fetched yet, it should be fine (the will not notice it). So I would consider --force as last resort and always consult the state of the repo with other members.
  • user247702
    user247702 almost 5 years
    @DanDascalescu how exactly can this "break" the repo? Reading your edit description, it sounds like you ran into a bug in an IDE or perhaps didn't pay close attention to what was happening? Adding such a vague warning to the answer isn't very helpful imho.
  • Dan Dascalescu
    Dan Dascalescu almost 5 years
    @Stijn: I don't recall what happened 5 years ago, and WebStorm might have had its share of the fault. As to how repos might be broken, I've merely linked to another highly upvoted answer that mentions that.
  • panzi
    panzi over 4 years
    If I do that git wants to rebase 46 commits, even though the commit in question is only 5 commits back. How can I be more specific about the exact commit?
  • sengi
    sengi over 4 years
    Git, like many other interactive command-line programs, will use whichever editor you've specified in your EDITOR environment variable. For example, if you add export EDITOR=emacs to your ~/.profile (assuming bash or similar shell) then it'll use Emacs.
  • Haoshu
    Haoshu over 4 years
    Are the first two steps equivalent to git checkout -b amending Commit1?
  • caiohamamura
    caiohamamura about 4 years
    Very nice workaround, this should be a default option to git amend to apply changes to a specific commit with the using the current stash, very clever!
  • revo
    revo almost 4 years
    This made me to resolve lots of conflicts... so I did git rebase --abort and didn't hesitate to commit another change instead of modifying the old one.
  • thrau
    thrau almost 4 years
    i wrote an alias for my .gitconfig to streamline this fixup = "!fn() { git commit --fixup ${1} && GIT_EDITOR=true git rebase --autosquash -i ${1}^; }; fn -> git fixup <commitId> amends all staged changes to the given commit
  • Toby 1 Kenobi
    Toby 1 Kenobi almost 4 years
    This is awesome! In my JetBrains IDE I can right click on the commit I want to edit and choose "iteractively rebase from here" and get a nice gui window that lets me choose which of the commit(s) to pause on for editing.
  • ambidexterous
    ambidexterous almost 4 years
    On windows single quotes ( ' ) around the commit id don't seem to work, so that first command will have to be git rebase -i "bbc643cd^" instead of git rebase -i 'bbc643cd^'
  • sissi_luaty
    sissi_luaty over 3 years
    The "reword" option is a good tool, however "git push --force" is dangerous. If the commits for which we want to change the commit message were not submitted yet, then --force is not necessary. The --force option rewrites the history at the remote rep, and requires more permissions. If you want to modify a commit that is only located on your computer, you do not need --force; if the commit was already pushed you shall not change it unless strictly necessary.
  • Big McLargeHuge
    Big McLargeHuge over 3 years
    Just FYI, I don't think the "$SHA1" argument to the rebase command works if it's the first commit.
  • Artem M
    Artem M over 3 years
    If you're unfamiliar to Vim, don't forget to press i to switch to the insert mode before changing pick to edit. Esc for exiting the insert mode.
  • Tim Visée
    Tim Visée about 3 years
    To edit the first commit, --root must be provided.
  • Roald
    Roald about 3 years
    Thanks @thrau! But it is missing a closing ".
  • Red
    Red over 2 years
    This is great answer for people scared with interactive rebase. My only gripe is that it's unnecessary to start from earlier commit and cherry-pick the actual commit you want to amend. You can just branch off the given commit and amend it as shown, skipping the cherrypick step. In fact, cherrypicking will just fastforward your branch one commit ahead, just as if you would branch directly off this commit.
  • Dominik
    Dominik over 2 years
    Consider to use --force-with-lease for push instead of just --force. It's safer. It does not overwrite all other stuff like from other contributors.
  • Jens Roland
    Jens Roland about 2 years
    Thraus alias doesn't seem to work with short commit hashes. This one works: fixup = "!fn() { git commit -m \"fixup! ${1}\" && GIT_EDITOR=true git rebase --autosquash -i ${1}^; }; fn"
  • RilDev
    RilDev about 2 years
    A video to show how the interactive rebase works: youtube.com/watch?v=tukOm3Afd8s&ab_channel=Ihatetomatoes