tags:

views:

45

answers:

2

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 git 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)?

Thanks.

+2  A: 

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.

earl
+2  A: 

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 a rebase --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:

)

alt text

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 tracks github/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 the git 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
VonC
This workflow using squash is pretty much what I want: http://www.braintreepaymentsolutions.com/devblog/our-git-workflow
namin
@namin: good alternative. I have included it in my answer, as well as adding some link illustrating the `git merge --squash`command.
VonC