Reputation: 77
I'm currently investigating how to move a subversion repo to git (bitbucket). The biggest blocker for me is understanding how to translate our current SVN based branches / merge strategy to git.
We practice something similar to "no junk in the trunk." Specifically, we have two branches (one for active development, one for staging / QA), and trunk (production):
dev ______________
\ \ \ (selective merges)
staging ___________
\ \ (selective merges)
trunk ________________________________
Practically speaking:
From a subversion vantage, it kinda looks like this:
svn checkout .../branches/dev
(ie: working in dev branch)svn commit -m "re ticket #1234"
(several commits could take place, and in the example they are revisions 100, 102, and 105)svn checkout .../branches/staging
(ie: working in staging branch)svn merge .../branches/dev -c 100,102,105
svn commit -m "re #1234 revs 100,102,105"
(this could then create revision 110)svn checkout .../trunk
(ie: working in trunk)svn merge .../branches/staging -c 110
(assuming that there is only one revision for this feature in staging... there could be more)svn commit -m "re #1234 revs 110"
This structure allows us to hit the following goals:
For all the googling around on git branch / merge strategies, the best solution I have seen involves topic / feature branches that then get merged into a main code line. This seems to involve a merge all or nothing process.
For the most part, I don't care if the process is functionally the same in git, but the features of the strategy are comparable.
Any pointers for the git newbie?
Thanks,
Mike
PS - After more digging, I came across the skullcandy workflow outlined here seems to be the closest to what I want to do. My best guess is that it would be done via git (with lots of bitbucket pull requests sprinkled in) like this (assuming two existing branches - master and staging):
git checkout master
git branch feature-001
git commit -a
git push -u origin feature-001
This seems like a good process. Best practice? I don't know.
After the process is completed, one "side effect" I don't understand is that bitbucket reports the staging branch is being behing and ahead of master?
Upvotes: 0
Views: 1254
Reputation: 164769
The workflow you outline at the end of your post is the basic Github workflow, but it has a flaw. Your feature branches are off of master
but they are merged into staging
and master
. This is the result after the first double merge.
- - - - - 5 [staging]
/ /
| Z - Y - X
|/ \
1 - 2 - 3 - - - - - 4 [master]
Note that while staging
and master
have the same content, they have different commit ids and histories. This will make things complicated. Not only will you have to resolve any merge conflicts twice (and possibly differently) but it kills a major feature of Git: the same commits have the same IDs.
Wait, it gets worse. Because you merge to staging
immediately, then QA, then merge to master
after QA, it's possible for features to be merged to master
and staging
in different orders. Not only does this produce a gross history, it can produce different merge conflicts with different resolutions. Now you really don't know if master
and staging
are the same. You can check with git diff master staging
but it'll be hard to track down where the differences leaked in and why.
- - - - - 5 - - - - 6 - 7 [staging]
/ / / /
/ / E - F - G -+-
/ / / / \
| Z - Y - X / J - K - L \
|/ \|/ \ \
1 - 2 - 3 - - - - - 4 - - - - - - 8 - 9 [master]
In this example, EFG
and JKL
both start from the same commit on master
. EFG
is merged into staging before JKL
, but JKL
completes QA first and is merged back into master
before EFG
. master
and staging
are now possibly different. Also your history graph is gross and hard to understand.
I guess you're using this Skullcandy workflow? I've never seen a workflow like that in practice where you habitually merge to two branches. It seems overly complicated. You're new to Git, keep it simple. Just branch from master and merge back into master. This produces a graph with the desirable "feature bubbles".
Z - Y - X J - K - L
/ \ / \
1 - 2 - 3 - - - - - 4 - - - - - 8 - 9 [master]
\ /
E - F - G - -
Now there is only one order in which features are merged.
Staging is not necessary in this workflow. Individual changes can be QA'd directly from the feature branch before merging back into master.
It would look like this...
git fetch origin; git checkout -b feature/1234 origin/master
git fetch origin
git rebase origin/master
.git merge origin/master
.git push -u origin feature/1234
.
feature/1234
.feature/1234
to master
.feature/1234
.
master
.
git merge --no-ff master
(or use Bitbucket's built in merging)git push origin :feature/1234
.git branch -d feature/1234
.The key difference is that the change is QA'd directly from the feature branch before merging. There's no need to maintain a separate staging branch and duplicate merging. No untested branches get merged into anything.
It's important to note that updating the feature branch by merging (or rebasing) master
into it has the same content as if you merged the feature branch into master
. This is why you can QA directly from the feature branch.
A staging
branch should instead be used to track what you're testing for the next release candidate. It's used as a stable spot for QA to shield the release candidate from changes to master
. It is nothing more than a spot on the normal history. In our example above, staging
might point to commit 2.
Also note that rather than doing one big git commit -a
when you're done with your feature, you can do small commits as you go. Fix a typo? Test & commit. Add a new method? Test & commit. Perform a refactoring? Test & commit. This breaks up your work into easy to understand chunks, it's much easier to map each line with an explanation of why it's there. When combined with testing, it makes debugging much easier. It was passing at the last commit, so it must be something changed since then. If your git diff
is small it will be easier to spot the change which caused the bug. If you decide a change was a bad idea, it's easier to throw just that change out.
My central philosophy is that under normal operation feature work should be isolated, merging should be simple and the dev branch should be ready for QA at all times. Developers shouldn't have to merge into multiple branches (like in Skullcandy). Cherry picking changes between branches should be an exceptional operation. The dev branch should be CI tested. Feature branches should be complete before merging to development. Staging and production should be simply older commits on the development branch.
Git is far more flexible than SVN, exceptional cases can be handled as they happen. If hot fixes and cherry picking are necessary, they should be rolled back into development as quickly as possible. You can even use rebase
to rewrite history and smooth everything out to make the normal flow work better. I know this idea of rewriting history probably freaks you out right now, you'll get used to it.
This makes development in branches faster and simpler and it increases the number of people who can review and merge changes.
Upvotes: 2