We use Subversion and aside from a few individuals such as myself there is little to no experience with branching and merging in Subversion. My Subversion experience is limited to simple feature branches where merge and tree-conflicts, while not exactly rare, are not exceedingly difficult to resolve.
Given that, I am helping to manage a project where our current commit to trunk method is simply unsustainable for our needs. I introduced feature branching and merging to my localized team and we had some success. However simple feature branching was still not able to answer all our questions such as:
- How do we develop code in parallel for this release and subsequent releases?
- What code is considered stable?
- What (in development) code is going into the next release?
- What (in development) code is going into a subsequent release?
- What version of code is our Test, Acceptance, or Production environments?
- How do we integrate concurrent development activities with a known stable release to reduce introducing bugs and incomplete work?
- How do we provide hot-fixes to released code?
- How do we know, from our source control, what development activity is currently ongoing?
- How do we experiment or R&D without disrupting the current code base while leveraging?
It seems that git-flow as defined here would go a long way to answer a lot of these questions. I experimented with this method in Mercurial and it seems like that it is possible to implement this method there as well. Sadly, migrating to a DVCS is off the table at this point.
However, my brief attempt to mimic this method in Subversion failed with many merge and tree conflicts. The merge options and edge cases are numerous and baffling.
Can Subversion be used to implement git-flow and if so what is the pain level?
We use what is called the unstable trunk development method. This was the development methodology that the creators of Subversion had in mind when they created Subversion. It's simple and easy to implement.
- You do all of your development on trunk. Thus called the unstable trunk.
- When you get close to a release, you make a branch for that release. The idea is to make the branch late enough to keep parallel development as short as possible, but not so later that some developers can't do their jobs because they no longer need to work on the current release, but need to start working on the next release. In Agile, this is usually done right before the firming sprint. It's usually done when the release is feature complete, and now you're just fixing bugs.
- The release takes place off of the branch. You tag off the branch. If there are patches that are needed, they're done off of the branch.
Here's an idea how it works:
- Imagine you're working on Release 1.2. You are working on the trunk. Now, you're getting close to the time when Release 1.2 is about to be released, and there's not enough work on Release 1.2 to keep your developers busy. You create a 1.2 branch for your release.
- Now, the people still working on Release 1.2 switch over to the Release 1.2 branch. Meanwhile, developers working on 1.3 stay on trunk.
- You are now ready to Release 1.2. You tag Release 1.2 right on the branch. The branch is not merged back into trunk. The trunk is for Release 1.3.
- Bugs are reported, and you want to fix them in Release 1.2.1. You continue working off the 1.2 branch. No new branch needed for 1.2.1. (You can lock branches between releases to keep them pure.
- When you are about to do Release 1.3, you repeat the process -- branch 1.3 and work for 1.4 continues on the trunk.
There will be some merging. It's mainly merging defects fixed on the release branch back to trunk. There are three options of doing this:
- Once you do a release, you merge enmass all changes on the branch back to trunk. There's very little tracking. You're just assuming that all the bug fixes on the branch also apply to the trunk.
- You use a tracking systems that understands issues may live on more than one release. In this case, you simply mark a bug discovered on the branch to trunk too. You can cherry pick changes that apply to trunk thanks to your issue tracking system.
- Some sites simply don't merge. They also track via the defect tracking system changes that need to be applied to the trunk that were applied on the branch, and simply re-implement them. They might copy changes from the branch to trunk, but they never do a formal merge. However, once you do this, you can't ever merge (unless you merge with the
--record-only
flag).
You, of course, realize that this method takes something called planning. You must prioritize your work, so the developers do the work for the upcoming release before work on the future release. You only branch once you no longer have enough work on the upcoming release to keep all of your developers busy.
You can implement the standard Git workflow which is using development separate development branches for each developer or issue, and then delivering those changes onto trunk. This would require a lot of branches, one for each developer/feature.
You first merge from the trunk to the branch to rebase your code. Once you've done the rebase, you merge from the branch back to the trunk using the --reintegrate
switch. Pre-1.6, you were suppose to delete the branch and recreate it since --reintegrate
sort of messed up merge tracking. However, this has been fixed in Release 1.6.x and up.