tags:

views:

237

answers:

2

I've been digging through the git merge and rebase docs, and something isn't sinking in. I'm actively working on a project in Git, and need to share specific milestones with other developers. I want to share the code exactly as it is at each milestone / release, but not all of my small commits leading up to each release.

How do I create a release branch that mirrors a development branch, where the commits on the release branch each contain several commits from the development branch? In other words, the release branch should have a compressed history, but otherwise match the development branch.

Originally, I had thought that using a separate branch and using git merge --squash would be effective, creating a new branch with a series of commits that reflect the full set of changes between each release. I now understand that git merge --squash doesn't work for repeated uses.

Git rebase would work to collapse several commits into one large commit, but because it changes the commit history, wouldn't change my private history as well as the public releases?

I don't want to lose my history of small changes, but want to push combined commits to a shared server.

+1  A: 

Just create a new branch and do all the squashing there. Then publish that. Your smaller commits will still be there in the other branches.

My Workflow for this would be somehow like that:

git co -b release_brach_ squash release_branshc_with_all_commits

git rebase last_relaose_tag

Now it's time to deal with all the conflicts that may arise. I don't really know how to avoid this. Usually it's not much of a problem though. My git repository has already recorded most conlict resolutions anyway.

git rebase --interactive last_release_tag

This will bring up vim. For all the releasse I want to squash I replace pick with squash. Then just save and quit. Done.

davrieb
Can you elaborate? From comments like http://stackoverflow.com/questions/1464642/git-merge-squash-repeatedly/1465119#1465119 it looks like repeated merge --squash isn't going to work. When I've tried this, I get very long lists of conflicts, even though the files have a common history. If I understand correctly, git merge --squash creates a new commit that doesn't share the history of the old commits, so future merges don't have common ancestors.You've described the behaviour I want, but I'm stumbling over getting Git to do it.
Neil
I've update the answer with my proposed workflow. Although I must admit Charles Bayleys solution might be bettter suited for your needs.
davrieb
+4  A: 

Surely, if your commits are both worth keeping and constitute your work towards a public release, then they should form part of your published history? If you don't want to publish your full repository history then you may be better off just using git archive to create release tarballs.

Having said that if you really want to create a release branch with a separate history then it is possible. You are setting yourself up for more maintenance overhead, though, as you can never merge from your private history to your public release branch as that would bring in all the private history to your release branch. This is what git does; it tracks where changes come from.

You can merge from the release branch to the private branch but as your work is (presumably) coming from the private branch this won't gain you much. Your easiest option is to have a separate release branch which contains only snapshot commits of the state of the private branch at release points.

Assuming that you have reached a point where you want to create a commit on the release branch (release) based on the current commit in the private branch (private) and assuming that you have the tree to be released checked out with no changes to the index, here is what you can do.

# Low-level plumbing command to switch branches without checking anything out
# (Note: it doesn't matter if this branch hasn't yet been created.)
git symbolic-ref HEAD refs/heads/release

# Create a new commit based on the current index in the release branch
git commit -m "Public release commit"

# Switch back to the private branch
git checkout private

You can do this for each release (or sub-release) and the new commit will be built directly on top of the previous release without incorporating any of your private history.

Charles Bailey
That certainly does it. Worked for me :)
James Cassell
Thanks, Charles. That does what I'm looking for.
Neil