开发者

Choosing Merge Direction

Consider a simple source-control layout, with a trunk representing a future release in development and a开发者_运维百科 single branch representing a release currently in production.

When a bug is discovered that needs fixed in both branches, should the change be made first to the trunk then merged down to the branch, or made first to the branch then merged up to the trunk? Typically I've made the fix first in the trunk then merged downwards, however there is an increased risk this way that future new features get merged down accidentally. What has worked best in your experience?


If the bugfix is in a checkin of its own (which is typically what you want to do), then there should be relatively little risk of merging new features along with the bugfix -- just select that single checkin as the revision to merge.

I see a greater risk in merging bugfixes from the branch from the trunk, namely that you can forget to do the merge. For the moment, everything looks fine -- the release version you're building from the branch has the fix. Only much later on will you discover that the bug is still in the trunk because you forgot to merge.

For this reason, I would prefer to fix in the trunk, then merge to the branch.


I always enforce a policy of fixing bugs in trunk first, and then merging it to the release branch.

I choose this because any change that has to be released needs to be reviewed, tested, and verified before going into the release branch. The release branch is a pristine copy of the code, and thus only reviewed, tested, and verified changes can go into it.


In systems that record full merge history (e.g. DAG-based systems like Git, Mercurial, and others), it may make the most sense to develop features and fixes on branches that are forked from the oldest place that will need the particular changes. This makes it easier to merge a finished branch into all the target branches.

You start out with just development.

 --o--o--o    development

Eventually, you decide the content is ready to be used. You make the production branch. Work continues on development, but that work is not yet suitable for production (which means that you should not try to merge development into production).

 --o--o--o--o         production
          \
           o--o--o    development

A bug is discovered and it needs to be fixed in both branches. The branch for the bug fix changes should be forked from a common ancestor of all the branches that will need the fix.

 --o--o--o--o             production
         |\
         | \------o--o    bugfix-1
          \
           o--o--o        development

Once the fix is ready, it is merged into both production and development. This is possible because bugfix-1 is forked from a common ancestor of both branches.

 --o--o--o--o----------o    production
         |\           /
         | \------o--o      bugfix-1
          \           \ 
           o--o--o-----o    development

Instead of just using the common ancestor, you might even fork the bug fix branch from the commit that introduced the bug. This will make sure the bug fix can be merged into any possible branch that itself incorporates the flawed commit (since in a fully distributed system, you might not know about all the branches that are using the flawed commit).

The “hotfix” branches from A successful Git branching model are a variation of this type of workflow. Git's maintainer has a blog post about the purposes of branches that might also help clarify how/why branches should be created and how to use them effectively when their content might be used in multiple descendent branches (e.g. why you might want to avoid merging an ‘upstream’ branch into a feature branch).


If you work the other way around (fork the bug fix branch from a commit that is only on one of your target branches), you will end up having to “replay” (i.e. “cherry pick” or “rebase”) individual changes from the bug fix branch to the other target branches instead of doing a normal merge. This method will work, but it means that you have to keep track of all the incarnations of the bug fix branch to verify whether a particular target branch contains (a version) of the bug fix (or fall back on manual code inspection).

Make bug fix “on top of” development.

 --o--o--o--o              production
          \
           o--o--o         development
                  \
                   b--b    bugfix-1

Merge it to development (example shows what is called a ‘non-fast-forward’ merge in Git), and rebase/cherry-pick the bug fix commits (b) on to production (b') since merging development into production would be a bad idea—not all of its content is ready for production:

 --o--o--o--o--b'--b'      production
          \
           o--o--o------o  development
                  \    /
                   b--b    bugfix-1

There is no recorded relationship between the b commits and the b' commits in the production branch. This lack of relationship means that you have to ask about both the b and the b' commits if you want to be able to answer the question “Does some branch, W, have the bug fix?” in an automated fashion.


Both options work pretty well. It really depends on where it makes the most sense on a per case basis.

Your scenarios of pain could also include fixing a bug in one branch and having to merge it to several other branches.

The bigger issue in older source control tools is remembering which 'patches' were applied where.

Many newer scm packages implement merges with GUID or other unique identifiers to make merge tracking easier.

In subversion before they introduced merge tracking it used to make sense to come up with a standardized checkin format for merges to make sure you could easily trace the merges across branches.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜