redefine a sequence of little commits into a logical unit commit
In some settings, I am used to using git locally, and then exporting a diff which is then submitting with a detailed description. Thus, when I develop locally, I commit constantly, and don't bother with meaningful commit messages or perfect testing before committing.
However, when using g开发者_开发问答it to publish code on github, I would prefer to erase the history of those little commits and create just one commit that represents logical well-tested change.
What would be the best way to achieve this, without changing my local workflow of committing whenever I feel like I've explored a little path (however unproven)?
If you look at "Trimming GIT Checkins/Squashing GIT History", you can:
git rebase --interactive --fixup
for squashing a commit you would have manually reordered in the commit edit list of arebase --interactive
, while ignoring the second commit message, which will make the message edition step faster (you can just save it: the squashed commit will have the first commit message only)git rebase --interactive --autosquash
for making the commit reordering process automatically for you.
That is why I like to pick a standard comment for all the micro-commits I make, per activity.
The first micro-commit will contain "my activity".
All the other will contain "squash! my activity
"
Several activities (set of micro-commits) can be intertwined in this process.
All there is left for you is a git rebase --interactive --autosquash
for all those micro-commits to be reordered and then squashed.
The OP namin mentions the blog post Our Git Workflow: Private Development, Public Releases as a good illustration, base on git merge --squash
:
(see also:
- In git, what is the difference between
merge --squash
andrebase
? - Git: after preparing a real merge commit, how to create a simple commit?
)
We maintain 3 branches for each of our client libraries:
master
— Active development occurs on this branch.release
— Development for bug fixes happens here. We also bump versions and update the changelog on this branch.github_master
— We squash commits from the release branch into single “release
” commits on this branch as well as tagging releases. This branch tracksgithub/master
.We’re now ready to move to the github_master branch.
git checkout github_master
We want to merge the changes from release into the github_master branch but we don’t want to see each individual commit.
Git helps us out here with thegit merge --squash
command. This will merge all the changes from a specific ref, squash them into a single set of changes and leave the changes staged. We commit the staged changes with the message “1.0.0” and tag the commit.
git merge --squash release
git commit -m "1.0.0"
git tag 1.0.0 -m "1.0.0"
With the commits squashed and tagged, it’s time to push to github.
We want to push the current branch’s HEAD to the master branch on the github remote.
git push github HEAD:master
Last but not least, we need to push these changes to the branches on origin and merge the squashed commit back to release and master.
You may suspect that git would be confused merging a squashed commit back into branches containing the non-collapsed commits, but it all works just as expected. Git is smart enough to realize no changes need to be made when merging in the squashed commit, but we should still merge to keep our branches in sync.
git push origin github_master
git checkout release
git merge github_master
git push origin release
git checkout master
git merge release
git push origin master
Have a look at the interactive mode of git-rebase. Basically, you would continue with your current workflow of many small commits. When it gets to pushing upstream, you would git rebase --interactive
back to the last commit you pushed upstream. Git will then present you with a list of your commits in an editor, allowing you to reorder, delete, combine, split, or reword your commits.
精彩评论