Git squash with a commit id You must type the word pick next to the commit you want all others to be squashed into. Then type 'squash', or just the letter 's', next to each commit to squash.
You can run git rebase --interactive
and reorder D before B and squash D into A.
Git will open an editor, and you see a file like this, ex: git rebase --interactive HEAD~4
pick aaaaaaa Commit A
pick bbbbbbb Commit B
pick ccccccc Commit C
pick ddddddd Commit D
# Rebase aaaaaaa..ddddddd onto 1234567 (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
Now you change the file that it looks like this:
pick aaaaaaa Commit A
squash ddddddd Commit D
pick bbbbbbb Commit B
pick ccccccc Commit C
And git will now meld the changes of A and D together into one commit, and put B and C afterwards. When you don't want to keep the commit message of D, instead of squash
, you would use the fixup
keyword. For more on fixup
, you can consult the git rebase
docs, or check out this question which has some good answers.
Note: You should not change commits that have been pushed to another repo in any way unless you know the consequences.
git log --oneline -4
D commit_message_for_D
C commit_message_for_C
B commit_message_for_B
A commit_message_for_A
git rebase --interactive
pick D commit_message_for_D
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
Type i
(Put VIM in insert mode)
Change the list to look like this (You don't have to remove or include the commit message). Do not misspell squash
!:
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D
Type Esc then ZZ
(Save and exit VIM)
# This is a combination of 2 commits.
# The first commit's message is:
commit_message_for_D
# This is the 2nd commit message:
commit_message_for_A
Type i
Change the text to what you want the new commit message to look like. I recommend this be a description of the changes in commit A
and D
:
new_commit_message_for_A_and_D
Type Esc then ZZ
git log --oneline -4
E new_commit_message_for_A_and_D
C commit_message_for_C
B commit_message_for_B
git show E
(You should see a diff showing a combination of changes from A and D)
You have now created a new commit E
. Commits A
and D
are no longer in your history but are not gone. You can still recover them at this point and for a while by git rebase --hard D
(git rebase --hard
will destroy any local changes!).
For those using SourceTree:
Make sure you haven't already pushed the commits.
Squash with previous
Interactive rebase works well until you have big feature branch with 20-30 commits and/or couple of merges from master or/and fixing conflicts while you was commiting in your branch. Even with finding my commits through history and replacing pick
with squash
doesn't worked here. So i was looking for another way and found this article.
I did my changes to work this on separate branch:
git checkout master
git fetch
git pull
git merge branch-name
git reset origin/master
git branch -D branch-name
git checkout -b branch-name
git add --all
#Do some commit
git push -f --set-upstream origin branch-name
Before this I got my pull request with about ~30 commits with 2-3 merges from master + fixing conflicts. And after this I got clear PR with one commit.
P.S. here is bash script to do this steps in automode.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With