I usually submit a list of commits for review. If I have the following commits:
HEAD
Commit3
Commit2
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?
git stash
+rebase
automationFor when I need to modify an old commit a lot of times for Gerrit reviews, I've been doing:
Usage:
git-amend-to $old_sha
I like this over
--autosquash
as it does not squash other unrelated fixups.I solved this,
1) by creating new commit with changes i want..
2) i know which commit i need to merge with it. which is commit 3.
so,
git rebase -i HEAD~4
# 4 represents recent 4 commit (here commit 3 is in 4th place)3) in interactive rebase recent commit will located at bottom. it will looks alike,
4) here we need to rearrange commit if you want to merge with specific one. it should be like,
after rearrange you need to replace
p
pick
withf
(fixup will merge without commit message) ors
(squash merge with commit message can change in run time)and then save your tree.
now merge done with existing commit.
To get a non-interactive command, put a script with this content in your PATH:
Use it by staging your changes (with
git add
) and then rungit fixup <commit-to-modify>
. Of course, it will still be interactive if you get conflicts.Use the awesome interactive rebase:
Find the commit you want, change
pick
toe
(edit
), and save and close the file. Git will rewind to that commit, allowing you to either:git commit --amend
to make changes, orgit 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 forHEAD
, 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:
* 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 withgit config --global core.editor your-favorite-text-editor
.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
toreword
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 messageIf you want to exit without applying the changes, press
:q!
EDIT: to navigate in
vim
you usej
to go up,k
to go down,h
to go left, andl
to go right( all this inNORMAL
mode, pressESC
to go toNORMAL
mode ). To edit a text, pressi
so that you enter theINSERT
mode, where you insert text. PressESC
to go back toNORMAL
mode :)UPDATE: Here's a great link from github listing How to undo (almost) anything with git
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
:Second, grab
Commit1
withcherry-pick
:Now, amend your changes, creating
Commit1'
:And finally, after having stashed any other changes, transplant the rest of your commits up to
master
on top of your new commit:Read: "rebase, onto the branch
amending
, all commits betweenCommit1
(non-inclusive) andmaster
(inclusive)". That is, Commit2 and Commit3, cutting the old Commit1 out entirely. You could just cherry-pick them, but this way is easier.Remember to clean up your branches!