Combining multiple commits before pushing in Git [duplicate]
I have a bunch of commits on my local repository which are thematically similar. I'd like to combine them into a single commit before pushing up to a remote. How do I do it? I think rebase
does this, but I can't make sense of the docs.
What you want to do is referred to as "squashing" in git. There are lots of options when you're doing this (too many?) but if you just want to merge all of your unpushed commits into a single commit, do this:
git rebase -i origin/master
This will bring up your text editor (-i
is for "interactive") with a file that looks like this:
pick 16b5fcc Code in, tests not passing
pick c964dea Getting closer
pick 06cf8ee Something changed
pick 396b4a3 Tests pass
pick 9be7fdb Better comments
pick 7dba9cb All done
Change all the pick
to squash
(or s
) except the first one:
pick 16b5fcc Code in, tests not passing
squash c964dea Getting closer
squash 06cf8ee Something changed
squash 396b4a3 Tests pass
squash 9be7fdb Better comments
squash 7dba9cb All done
Save your file and exit your editor. Then another text editor will open to let you combine the commit messages from all of the commits into one big commit message.
Voila! Googling "git squashing" will give you explanations of all the other options available.
If you have lots of commits and you only want to squash the last X commits, find the commit ID of the commit from which you want to start squashing and do
git rebase -i <that_commit_id>
Then proceed as described in leopd's answer, changing all the pick
s to squash
es except the first one.
Example:
871adf OK, feature Z is fully implemented --- newer commit --┐
0c3317 Whoops, not yet... |
87871a I'm ready! |
643d0e Code cleanup |-- Join these into one
afb581 Fix this and that |
4e9baa Cool implementation |
d94e78 Prepare the workbench for feature Z -------------------┘
6394dc Feature Y --- older commit
You can either do this (write the number of commits):
git rebase --interactive HEAD~[7]
Or this (write the hash of the last commit you don't want to squash):
git rebase --interactive 6394dc
There are quite a few working answers here, but I found this the easiest. This command will open up an editor, where you can just replace pick
with squash
in order to remove/merge them into one
git rebase -i HEAD~4
where, 4
is the number of commits you want to squash into one. This is explained here as well.
If you are looking to squash
the commits which also includes the very first commit, then use this command
git rebase -i --root
You can do this with git rebase -i
, passing in the revision that you want to use as the 'root':
git rebase -i origin/master
will open an editor window showing all of the commits you have made after the last commit in origin/master
. You can reject commits, squash commits into a single commit, or edit previous commits.
There are a few resources that can probably explain this in a better way, and show some other examples:
http://book.git-scm.com/4_interactive_rebasing.html
and
http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html
are the first two good pages I could find.
I came up with
#!/bin/sh
message=`git log --format=%B origin..HEAD | sort | uniq | grep -v '^$'`
git reset --soft origin
git commit -m "$message"
Combines, sorts, unifies and remove empty lines from the commit message. I use this for local changes to a github wiki (using gollum)
You can squash (join) commits with an Interactive Rebase. There is a pretty nice YouTube video which shows how to do this on the command line or with SmartGit:
- https://www.youtube.com/watch?v=qi_QAFrmHJM
If you are already a SmartGit user then you can select all your outgoing commits (by holding down the Ctrl key) and open the context menu (right click) to squash your commits.
It's very comfortable:
There is also a very nice tutorial from Atlassian which shows how it works:
- https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase-i
And my way of squashing
multiple push
is (perhaps you pushed to your own branch many commits and now you wish to do a pull request and you don't want to clutter them with many commits which you have already pushed). The way I do that (no other simpler option as far as I can tell is).
- Create new branch for the sake of
squash
(branch from the original branch you wish to pull request to). - Push the newly created branch.
- Merge branch with commits (already pushed) to new branch.
- Rebase new branch and squash.
- Push new branch.
- Create new pull request for new branch which now has single commit.
Example:
git checkout from_branch_you_wish_to_pull_request_to
git checkout -b new_branch_will_have_single_squashed_commit
git push -u new_branch_will_have_single_squashed_commit
git merge older_branch_with_all_those_multiple_commits
git rebase -i (here you squash)
git push origin new_branch_will_have_single_squashed_commit
You can now pull request into from_branch_you_wish_to_pull_request_to
You probably want to use Interactive Rebasing, which is described in detail in that link.
You can find other good resources if you search for "git rebase interactive".
精彩评论