How to amend older Git commit?

146,090

Solution 1

git rebase -i HEAD^^^

Now mark the ones you want to amend with edit or e (replace pick). Now save and exit.

Now make your changes, then

git add .
git rebase --continue

If you want to add an extra delete remove the options from the commit command. If you want to adjust the message, omit just the --no-edit option.

Solution 2

I prepared my commit that I wanted to amend with an older one and was surprised to see that rebase -i complained that I have uncommitted changes. But I didn't want to make my changes again specifying edit option of the older commit. So the solution was pretty easy and straightforward:

  1. prepare your update to older commit, add it and commit
  2. git rebase -i <commit you want to amend>^ - notice the ^ so you see the said commit in the text editor
  3. you will get sometihng like this:

    pick 8c83e24 use substitution instead of separate subsystems file to avoid jgroups.xml and jgroups-e2.xml going out of sync
    pick 799ce28 generate ec2 configuration out of subsystems-ha.xml and subsystems-full-ha.xml to avoid discrepancies
    pick e23d23a fix indentation of jgroups.xml
    
  4. now to combine e23d23a with 8c83e24 you can change line order and use squash like this:

    pick 8c83e24 use substitution instead of separate subsystems file to avoid jgroups.xml and jgroups-e2.xml going out of sync    
    squash e23d23a fix indentation of jgroups.xml
    pick 799ce28 generate ec2 configuration out of subsystems-ha.xml and subsystems-full-ha.xml to avoid discrepancies
    
  5. write and exit the file, you will be present with an editor to merge the commit messages. Do so and save/exit the text document

  6. You are done, your commits are amended

credit goes to: http://git-scm.com/book/en/Git-Tools-Rewriting-History There's also other useful demonstrated git magic.

Solution 3

I've used another way for a few times. In fact, it is a manual git rebase -i and it is useful when you want to rearrange several commits including squashing or splitting some of them. The main advantage is that you don't have to decide about every commit's destiny at a single moment. You'll also have all Git features available during the process unlike during a rebase. For example, you can display the log of both original and rewritten history at any time, or even do another rebase!

I'll refer to the commits in the following way, so it's readable easily:

C # good commit after a bad one
B # bad commit
A # good commit before a bad one

Your history in the beginning looks like this:

x - A - B - C
|           |
|           master
|
origin/master

We'll recreate it to this way:

x - A - B*- C'
|           |
|           master
|
origin/master

Procedure

git checkout B       # get working-tree to the state of commit B
git reset --soft A   # tell Git that we are working before commit B
git checkout -b rewrite-history   # switch to a new branch for alternative history

Improve your old commit using git add (git add -i, git stash etc.) now. You can even split your old commit into two or more.

git commit           # recreate commit B (result = B*)
git cherry-pick C    # copy C to our new branch (result = C')

Intermediate result:

x - A - B - C 
|    \      |
|     \     master
|      \
|       B*- C'
|           |
|           rewrite-history
|
origin/master

Let's finish:

git checkout master
git reset --hard rewrite-history  # make this branch master

Or using just one command:

git branch -f master  # make this place the new tip of the master branch

That's it, you can push your progress now.

The last task is to delete the temporary branch:

git branch -d rewrite-history

Solution 4

You could can use git rebase to rewrite the commit history. This can be potentially destructive to your changes, so use with care.

First commit your "amend" change as a normal commit. Then do an interactive rebase starting on the parent of your oldest commit

git rebase -i 47175e84c2cb7e47520f7dde824718eae3624550^

This will fire up your editor with all commits. Reorder them so your "amend" commit comes below the one you want to amend. Then replace the first word on the line with the "amend" commit with s which will combine (s quash) it with the commit before. Save and exit your editor and follow the instructions.

Solution 5

You can use git rebase --interactive, using the edit command on the commit you want to amend.

Share:
146,090

Related videos on Youtube

michael
Author by

michael

Updated on July 08, 2022

Comments

  • michael
    michael almost 2 years

    I have made 3 git commits, but have not been pushed. How can I amend the older one (ddc6859af44) and (47175e84c) which is not the most recent one?

    $git log
    commit f4074f289b8a49250b15a4f25ca4b46017454781
    Date:   Tue Jan 10 10:57:27 2012 -0800
    
    commit ddc6859af448b8fd2e86dd0437c47b6014380a7f
    Date:   Mon Jan 9 16:29:30 2012 -0800
    
    commit 47175e84c2cb7e47520f7dde824718eae3624550
    Date:   Mon Jan 9 13:13:22 2012 -0800
    
    • Adam Dymitruk
      Adam Dymitruk over 12 years
      Please clarify if you want to combine those 2 commits into 1 commit or if you want to amend each one with further changes.
    • Colin O'Dell
      Colin O'Dell almost 10 years
      I've created a Bash script for this exact purpose: github.com/colinodell/git-amend-old Once installed, you'd use it like this: git amend-old abcd123, where abcd123 is the old commit you want to amend with your staged changes. Hope somebody finds it useful!
  • Adam Dymitruk
    Adam Dymitruk over 12 years
    He does not want to squash or reorder the commits.
  • Benjamin Bannier
    Benjamin Bannier over 12 years
    @AdamDymitruk: Where does he say that? Btw, your answer also suggests rewriting the history.
  • Adam Dymitruk
    Adam Dymitruk over 12 years
    he just wants to amend. no mention of squashing commits together or reordering them.
  • Benjamin Bannier
    Benjamin Bannier over 12 years
    @AdamDymitruk: amending is a short-hand for committing & squashing the last two commits. Both change the commit SHA1 ("rewrite history"). Please educate me if I have a wrong mental picture.
  • Adam Dymitruk
    Adam Dymitruk over 12 years
    you can amend both commits. Squashing is squashing. Amending is something else.
  • Adam Dymitruk
    Adam Dymitruk over 12 years
    I've added a comment on the question requesting clarification from the OP. As it reads now, I've interpreted it as him wanting to change those 2 commits and not squash or reorder them.
  • Benjamin Bannier
    Benjamin Bannier over 12 years
    I am pretty sure you are confused what amend does. Make a test project and do what I say and what you say and compare.
  • Adam Dymitruk
    Adam Dymitruk over 12 years
    amend adds to the last commit - whether you are in a rebase or not. Squash takes 2 existing commits and makes them into 1. What am I missing?
  • Benjamin Bannier
    Benjamin Bannier over 12 years
    You are missing that they both result in new tree object which does contain exactly the same content.
  • Adam Dymitruk
    Adam Dymitruk over 12 years
    dear God. It's like pulling teeth. Do you think I don't understand how the DAG is structured? Which of the 564 Git questions that I answered in the last 2+ years lead you to believe this? The issue is whether he wants to amend each of the 2 commits, or if he means that he wants to squash them into one. That is the common terminology.
  • Benjamin Bannier
    Benjamin Bannier over 12 years
    Don't get upset, you brought up the nitpicking. And that was exactly what led me to believe you didn't understand what git was doing internally.
  • Adam Dymitruk
    Adam Dymitruk over 12 years
    I'm not upset. We should have listened to the suggestion and went to chat :)
  • Benjamin Bannier
    Benjamin Bannier over 12 years
  • Dan Bechard
    Dan Bechard about 10 years
    I didn't realize I could reorder the lines in the rebase file. Great tip!
  • here
    here over 9 years
    It may be convenient to use git stash or git stash [-p|--patch] (interactive) to easily apply the changes to an older commit during a rebase.
  • manyways
    manyways over 8 years
    Note - you don't have to git commit after git add -A, simply git rebase --continue will keep your changes.
  • konsolebox
    konsolebox almost 8 years
    I found this answer easier to understand.
  • kleinfreund
    kleinfreund over 6 years
    no matches found: HEAD^^^
  • Jacob
    Jacob over 6 years
    @kleinfreund You've probably solved that after two years, but for anyone else (like me) with that problem: some shells (like zsh) parse ^ as a pattern. You can use ~ instead in that case.
  • flopshot
    flopshot over 5 years
    if anyone is unfamiliar with the vi commands to edit a file in the terminal, this page is a very good reference cs.colostate.edu/helpdocs/vi.html
  • DarkFranX
    DarkFranX over 5 years
    What does the triple ^ do?
  • Adam Dymitruk
    Adam Dymitruk over 5 years
    You can escape the ^ with a /. Each ^ means parent and implies first parent. ^ is the same as ^1. Look up "treeish" in the git manual. ~ is a way of shortening a few ^ together. ^^^ and ~3 are equivalent.
  • CLOVIS
    CLOVIS about 5 years
    @DarkFranX "HEAD^^^" means "3 commits before head"
  • BenKoshy
    BenKoshy about 4 years
    @DanBechard be careful when you reorder lines: if you accidentally cut and forget to paste: that commit is gone!!
  • mehov
    mehov about 2 years
    Alternatively, git rebase -i HEAD~N to go last N commits back (saves having to type multiple ^)