I switched my team over to GIT about a month ago. For the most part it has been ok, a few small problems here and there, a lot of learning. We ran into a situation that caused us quite a headache recently with changes that are not to go live being already in master. We had this same problem when using SVN, so it was not new, just crappy, as it always is. We had spent the last month however playing with GIT and we were all now very clear on how easy branching is in GIT. We decided at that point that we would adopt a more GITy approach to development and create new branches for all changes then only ‘merge’ them into master when they had been completed. This is when I started to do more research on rebasing…
Note: I want to point out, this is about rebasing between branches from a remote repo that multiple people are could be working on. Rebasing in a single branch is/with only local work is…well, read about it somewhere else. It is easy.
What is rebase? What does it do?
Rebase is like a merge, the difference is that it preserve the commit history. As Shakespeare once wrote, “Words, words, words!”. Here:
So, that is really it, instead of having a single “merge commit” you get the entire commit history.
Why would you want this? Well, our workflow is to work on a new feature (or bug fix) in a new branch, then when it is done move those changes into master and delete the branch. The problems is if you just use merge, you will end up with a master that is nothing but merge commits, so its revision history is pretty worthless. With rebase, we can get rid of the branch, but not lose its history. As far as we are concerned, once the feature is done, it is just “part of the projects past” and we don’t want to dig down into old broken branches if we need to go back to it.
Sounds cool, but someone else already rebased their changes into master? / OH GOD EVERYTHING IS BLOWING UP
Ah yes, this is where it gets a little tricky. So, say we have a team of multiple people, all working on their own branches, someone finishes their work, rebases it into master, now my branch is not coming off of origin/master…this does not seem good.
Yeah, so I wish I had a picture for this, but I started making one and I got tired.
You have 2 choices at this point.
You can rebase master back into your branch
This is what I tried first. This shoves all of the changes that were added to master to the bottom of your branch. This means your local branches commit history has changed and if you try to push, you will get an error. Basically, your local branch now looks like a totally different branch from what is in origin, this is bound to cause problems. You can do a “force push” which will basically says ‘screw what is in origin, use this’ which works, it is just crappy for anyone else working on that branch because everything goes a bit wonky.
Note: People have been questioning me about what I said above. If your branch is only local (ie: has never been push, only committed to) you don’t have to force push because it does not exist in origin yet, so origin can’t complain. Also, if you are the only person who has done any work on the branch, doing a force isn’t really all that bad as you can only hurt yourself. I unfortunately do not have the luxury of working in an environment where either of these is usually the case.
You can merge master into your branch
This seems to be the way to go. Doing this means your commit history stays the same and you just get the changes that were added to master after you branched as a ‘merge commit’. Now, when your branch is done and you rebase back into master, you are already up to date with what is there, and it can easily add the commits from your branch on to the top of master.
This won’t look as pretty as always rebasing. If you rebase it makes it appear that your branch is always coming off of the latest version of master. If you merge, your branch will come off of master, then come back together where you merge, and basically flow in and out as you merge/make changes. But then again, we are planning on deleting the branch when it is done anyway, so who cares if it does not look super pretty…Also, I guess as long as the workflow is good, I should not be caring about the prettyness of my repo, stupid brain!
Recap
Workflow: when you start working, you create a branch off of master and make your changes. If changes are made to master (say someone finishes the changes in their branch and rebases it into master) while you are working, merge them back into your branch. When your branch is done, rebase it into master and delete the branch.
Basically, you only ever rebase master. Other branches should have changes from master merged into them.
Is this the commonly accepted workflow? Uh..sure…why not? It is here. I would change it if someone proposed something better. Like I said, I have spent a lot of time reading about these things, there is a lot of information…I just don’t see a lot of information that answers the question I had when trying to figure all of this out.
I wrote this up because even though there is tons of information about all these things online, nobody seems to provide it in a manner that was clear to me until I spent a good deal of time playing with it myself…I have probably not really helped that either.
PS: Yes, I am very well aware of how lame and I am sure over-done the joke (if you can even call it that) in my title is. I am lame.
hi!!!
Argh, brainfart, I shmeoow completely missed the third paragraph The git svn branch part is really just the branch creation (like svn cp trunk branch ). After that, you should have a new remote tracking branch (see git branch -r ) and can rebase your stuff onto it, like:git rebase onto $new_svn_branch master $git_branchWhat that does is that it turns the commits in the range master..$git_branch into patches, applies them on top of $new_svn_branch and then updates $git_branch to reference the result.And then git svn dcommit -n should tell you that it’s going to dcommit your stuff to the new svn branch.
By the way, I just verified that Git does not allow one to tdeele all branches from a *local* repo. Once you’ve committed the first commit to the initial branch (default is master’), it seems that you cannot tdeele this branch. I suppose this makes sense because it would be very dangerous to allow a user to tdeele the entire main history of a repo. It follows from this reasoning that Git should also disallow the deletion of all branches in a remote repo, but I haven’t yet verified that this is true.