|
|
Should TFS Source Control support the idea that two sibling branches are actually related and that baseless merging is not the easiest between sibling branches that actually have a relationship?
This is meant more as a topic of discussion to further the ability to understand TFS and why baseless merging vs. giving the merge a base is supported.
Thanks in advance for further comments.
|
|
|
|
|
As you know, TFS does not automatically create a merge relationship between two sibling branches (that share the same parent). This is by design. The VSTS Rangers Guidance II suggests avoiding baseless merges for normal merging scenarios.
The best way to merge changes from sibling (source) to another sibling (target) branch is to RI the change first to the parent branch and then FI the change to the sibling (target) branch. A huge risk with doing a sibling->sibling
merge is that future siblings (which branch from the same parent) won't have the change since it was never RI'd back to the parent branch.
As you know, baseless merges introduce a myriad of problems including:
- Conflicts cannot be auto-merged
- Deletes are not propagated
Bill Heys
VSTS Ranger
|
|
|
|
|
I have a normal scenario in which I use a baseless merge at least twice a week.
Perhaps I can solicit your help in resolving the reason behind the baseless merge.
I do a lot of feature branches. (I really enjoy having a feature in or out of the codebase.)
Periodically I would like to refresh our feature branches to our trunk. (I call it a merge up.)
This idea works well until it is time to merge back down. Then I get a ton of conflicts that have nothing to do with my feature.
So instead I have been creating a new sibling branch from trunk and then baseless merging the base of the other sibling and then merging down all code for the feature to the new sibling.
Then when it is time to merge to trunk I am only merging feature changes. This helps me with risk, but as I noted the baseless merge is required to give the two siblings a base.
I have found another way since writing the original email. It involves a tfpt migration of shelvesets, but it results in the same branch state.
How would you propose a merge up/merge back down scenario to work?
The other situation in which this occurs is dependent features that are not ready yet. Any proposals on that scenario would be much appreciated as well.
|
|
|
|
|
Let me try to address your approach.
I don't have a particular objection for having lots of feature branches. In my experience the relationship between the Main branch and the Feature branch tends to work in the inverse of how you describe your scenario.
When you are doing a "merge up" to periodically refresh your feature branches
to your trunk (main branch), you are no longer keeping that feature out of the code base.
I am concerned that you are periodically doing a merge up rather than merging a feature branch back to the main branch only once the development in the feature branch is ready and has passed the quality gates set for merging up.
The goal we are striving for in our guidance is to have the main branch (trunk) be as stable as possible. Doing periodic refreshes from feature branches, especially if the integration of these features with the code base has not been done and tested before
merging up, seems to me would make the main branch unstable for a period of time. I do not recommend testing the integration of new feature in the Main branch for the first time. Rather I merge (FI or merge down) the Main branch into the feature branch
and test the integration in the Dev feature branch first.
Our guidance suggests keeping the Main branch sync'd on a regular basis with the various feature branches. Having lots of feature branches does provide isolation (too much isolation?) and does multiply the effort for keeping the Main branch in sync with
the Dev feature branches. Working the way, integration instability is introduced first into the Dev branch not into the Main branch.
By keeping Main sync'd with the Dev branches on a regular (daily?) basis, you avoid having a ton of conflicts all at one time. And, I would think, when you do have merge conflicts going from Main into Dev, it would be directly related to the feature.
There are so many risks with doing sibling to sibling baseless merges, as I mentioned on my prior response.. Even on complex projects we have found better ways.
Regards.
Bill
|
|
|
|
|
what you describe is exactly what I am doing. I always code and introduce merges and features in feature branches. I just call a merge up what you call a merge down.
So for me "merge up" means main to feature branch and "merge down" means feature to main.
Your daily merge from main to the dev branches creates changes to the feature branch that then conflict when moved back to main in TFS Source Control.
Your other possibility is to discard the changeset that represent your merges from main to dev branches back and remove them from the dev to main merge needed report.
This can cause issues as you will lose your integrations that were made in order to incorporate the merge.
Perhaps you miss how I am doing the baseless merge.
Let's walk through a scenario
I have a stable main.
I create a feature branch I will call FeatureA. This checkin is committed on changeset X1111 and further checkins on the branch reach changset X2222.
Time comes when I become so out of sync with main that my isolation is ineffective.
So I decide I need a merge with the main, but I am not done and tested with my feature so I can't very well merge to my main stable branch.
In your methodology, you would merge main to FeatureA creating changeset X2223. If you view your merge report you would need to merge X2223 from dev to main.
Odd because you got the changeset from main, but it makes sense becuase you actually edited FeatureA branch in some way to incorporate the main changes.
In my way, I create a new feature branch from the tip of main called FeatureA+1. I then do a baseless discard merge with FeatureA changeset X1111 to create links between all files.
I checkin. I then do a merge with FeatureA /version:X1111+1~X2222. I check in. I now have all the changes of the featureA on featureA+1 nice and concise and ready to go
I haven't changed main and I can merge only those changes of FeatureA that make sense.
|
|
|
|
|
Let's start by using a consistent terminology with respect to merging. Different people draw the relationship between Main and Dev. Some have Dev above Main (as in our guidance). TFS 2010 shows it below main in the hierarcy view. So merge up or down can
be confusing. I propose to always use the terminology merge (forward integration) or (FI) when going from parent to child, in our case Main to Dev. and merge (reverse integration) or (RI) when going from child to parent, in our case Dev to Main.
It wasn't clear from your earlier description ("I would like to refresh our feature branches to our trunk. (I call it a merge up)" that you were going from Main to Feature rather than Feature to Main. So as long as we are clear, you are doing
an FI from Main to Dev on a regular (even daily basis).
Before you do the merge back to Main from a Dev branch you should be doing one last FI from Main to Dev. If you resolve those conflicts prior to doing the RI from Dev to Main, you should be able to accept all changes from source when you merge back.
I am not sure I understand the statement "Time comes when I become so out of sync with main that my isolation is ineffective." We are recommending that you NEVER get so out of sync with Main. Rather we recommend doing a frequent and regular merge
(FI) from Main to Dev to prevent the two from getting very far out of sync.
When you are done with feature dev in Dev. and you have reached your predetermined quality gates, do one last FI from Main to Dev test the integation in Dev and then do your RI from Dev to Main and Main should remain pretty stable. Main now has the new feature
- ready for QA.
I am not sure you necessarily end up with a different result with your baseless merge. I haven't tried it (but I will). But I can do everything from within VSTS (no baseless merges)
How do you deal with deletes?
Bill Heys
VSTS Rangers
|
|
|
|
|
deletes are only a problem when the feature makes a change to a file that was deleted in main.
TFS handles/throws up on these as the file linking to complete the feature merge cannot complete successfully and therefore I can easily see that a file does not make it in.
I suggest you attempt to do an FI with a serious conflict (preferably a change someone else did and you don't understand.) and then do an RI and ask yourself your comfort level with merging someone else's changes in this manner and only testing your feature.
The statement "Time comes when I become so out of sync with main that my isolation is ineffective." basically comes down to when to do these FIs.
If the statement is true that a difficult FI will produce a difficult RI for the future then the idea of frequent FIs becomes more cumbersome than you might think.
Also when you do your RI look at the list of files in your changeset and ask yourself why FeatureA changed that file. In many cases, you are changing files that have nothing to do with your feature which is code churn.
I started with the way you are describing. I agree 100% with the theory. I wish TFS Source Control worked for me in the way you are describing.
Right now I am misunderstanding TFS Source Control because the moment I do an FI TFS Source Control requires an RI with the exact same changes and conflicts.
|
|
|
|
|
I hope this discussion can continue because it is important to me that I should not be using baseless merges. Had the designers intended baseless merges to be used as oft as I use them, they would have made the UI support a baseless merge.
What I am describing is essentially a 3 way merge or merge where I provide the base. I use the baseless merge and discard functionality to provide the base.
This is how I came to the conclusion that discussing a need for based merges/3 way merges might be an answer to some of my woes.
|
|
|
|
|
I am happy to continue this discussion, but I didn't think we were making much progress in reaching consensus.
I wonder if we should take it offline as we hash out our "differences", and then come back online to summarize where we end up.
Bill
bill.heys@microsoft.com
|
|
|
|
|
There definitely seems to be some flaky behavior with TFS and reparenting. Sometimes the option is available and sometimes it's not. I also was hoping to find some insight on how to do changeset based merging (using Microsoft's best practices).
|
|
|
|
|
Reparenting requires certain conditions to exist before it is a valid option. First, you can only reparent branches, this option is not available for branched folders. Second, there must already be a merge relationship between the child branch being reparented
and the new parent branch. If you select a branch that has only a single merge relationship (with its current parent), reparenting will not be available. If you are seeing *flaky* behavior when these conditions are true, please let us know.
I am not sure what advice to offer on changeset-based merging (cherry picking). The Ranger's branching guidance cautions against cherry picking. What are you trying to achieve, and why do you feel that changeset-based merges are necessary?
Regards,
Bill Heys
VS ALM Ranger
|
|
|
|
|
Thanks for your insights Bill.
For the reparenting issue, if a release more closely resembles a prior release instead of the stable build on main (as in the case of the interim release - which includes some bug fixes, and a select few features that are solid) it is convenient to branch
from the prior release (release 2.1 branches from release 2). However, if you are not redistributing release 2 (as in the case of a web app), but rather "locking" or archiving it, you need to reparent to main so you can merge bug fixes
back to the DEV branch. In order to do this you have to perform a baseless merge (although I wouldn't consider it baseless, as it starts with the same base). I think the reparenting feature should support this. The one time I was able to
do this using the UI to reparent version 2.2 (descendent of 2.1) back to main was after I installed the hotfix for the branch by label issue. So I presumed that the hotfix now allowed reparenting up the graph.
In our typical release cycle, we meet every month and determine what on our DEV branch is ready to release. The changesets are mapped to defect numbers (or work items). Only stuff that passes SIT and is in scope (we have dependent systems) gets
pulled into the release. So a branch is made, code is merged in from main, and the release is staged. For the UAT cycle, the fixes to the release are performed in that branch. Once the release goes live, the branch is locked, changes are
reverse integrated into main and then FI to DEV. Development on the next cycle resumes (and/or continues) in DEV (where we can continue on features slated for release 3.x). I would say this is the most typical approach for web development.
So if changeset-based (or work-item based) merging is discouraged, then why does TFS support it? To me it feels like TFS is not fully supporting it because the merge engine isn't robust enough yet to support it, yet they know the feature is important.
To me it seems like an essential part of development for large projects. How would you handle this scenario?
Thanks,
Doug
|
|
|
Dec 9 2010 at 5:13 PM
Edited Dec 9 2010 at 5:14 PM
|
fastboxster wrote:
So if changeset-based (or work-item based) merging is discouraged, then why does TFS support it? To me it feels like TFS is not fully supporting it because the merge engine isn't robust enough yet to support it, yet they know the feature is important.
To me it seems like an essential part of development for large projects. How would you handle this scenario?
Thanks,
Doug
We have not said, I don't believe, that the *tool*, TFS does not fully support changeset-based merging (cherry picking). There are many challenges one needs to understand before making cherry picking a standard merge approach.
Let's use the following scenario:
- New classes, File01.cs and File02 are created and checked in (Changeset #001)
- Modifications are made to File01 and File02 and checked in together (Changeset #002)
- Modifications to fix a bug in File02 are checked in (Changeset #003)
- Modifications to fix a bug in File01 are checked in (Changeset #004)
- File01 and File02 are refactored, and changes are checked in (Changeset #005)
- Bug fix to File 01 is checed in (Changeset #006)
- Bug fix to File 02 is checked in (Changeset #007)
And so on.
Do you decide in advance that File01 and File02 are part of the same feature and should either be released together or not-released until both are ready?
Are the changes to File01 and File02 both attached to the same Work Item?
How do you ensure that all of the changesets involving both File01 and File02 are correctly merged (the problem of not merging enough).
- What happens if Changest #004 is not picked up in the merge?
- How do you prevent this problem?
- How do you detect this problem?
- How do you fix this problem?
How do you ensure that every time a change is checked in (and a new changeset is created) that it is properly associated to the correct work item?
- What happens if the developer fails to associate the change with a work item?
- What happens if the devloper associates the change with the wrong work item?
- How do you prevent this problem?
- How do you detect this problem?
- How do you fix this problem?
What happens, after you do this first cherry picking merge, if subsequent bug fixes or enhancements are made to file01 and / or file02?
- How do you ensure that this bug fix is picked up in the next merge?
- How do you avoid re-merging changesets that have already been merged?
- How do you avoid a merge that takes a stable (bug-free) component in the target branch and introduces a new bug because of an incomplete merge (merge too little) or invalid merge (merge too much).
What happens if you discover while testing file01 and file02 that there is a bug in file03 that needs to be resolved before you can release file01 and file02?
- How do you add this new bug to the release?
- How do you ensure that you do not merge too little? For example, is it possible to merge just the bug-fix changeset to file03 - without merging all the predecessors changes fo file03. Wouldn't this leave file03 in an unstable state?
I could continue, but I think the point I am making is that when you do cherry picking merges as a part of your regular develop/test/stabilize/release process you have to be much more careful and rely on your developers being much more careful all along
the way. The risk is that it is far easier to introduce bugs into the target branch when you rely on cherry picking rather than merging the latest version of a branch that has been stablized. I am not saying the tools (TFS) cannot or do not support it.
But to be clear, no tool will be capable of making sure you cherry pick the changes you want, and only the changes you want, and all of the changes you need to ensure the target branch has just the right changes (not too much and not too little).
The caution against cherry picking is more becuase of the challenges to the process than with the tools.
Regards,
Bill Heys
VS ALM Ranger
|
|
|
|
|
fastboxster wrote:
For the reparenting issue, if a release more closely resembles a prior release instead of the stable build on main (as in the case of the interim release - which includes some bug fixes, and a select few features that are solid) it is convenient to branch
from the prior release (release 2.1 branches from release 2). However, if you are not redistributing release 2 (as in the case of a web app), but rather "locking" or archiving it, you need to reparent to main so you can merge bug fixes
back to the DEV branch. In order to do this you have to perform a baseless merge (although I wouldn't consider it baseless, as it starts with the same base). I think the reparenting feature should support this. The one time I was able to
do this using the UI to reparent version 2.2 (descendent of 2.1) back to main was after I installed the hotfix for the branch by label issue. So I presumed that the hotfix now allowed reparenting up the graph.
Doug
What you seem to be describing is a variation of either the Standard or Advanced branch plan. If you refer to the Rangers Branching Guidance 2010, you will note that in the Standard branch plan, there is a Servicing (or Service Pack) branch between
the Main branch and the Release branch. When the code in Main (for release 2) is stable and ready to release, you would branch Main to ServicePack (for release 2) and branch ServicePack to Release (for release 2). You would ship from the Release branch (for
release 2) and lock it down (make it read-only for safekeeping).
After shipping Release 2, you might have to make some hotfixes or you may want to ship a service pack (minor release 2.1). You make these bug fixes in the Servicing (or ServicePack) branch for Release 2 and ship them as Release 2.1. If you need a safekeeping
copy of Release 2.1, you can branch it (once stable and ready to ship) to a new Release 2.1 branch (which you make read-only)
Each time you ship a hot fix or service pack for Release 2 you make these changes in the service pack branch for Release 2 and ship from there. Since the ServicePack branch is a full-child of Main there is a merge relationship that allows you to merge (Reverse
Integrate) changes back into Main (and then into the Dev branches if desired).
All of this is done without baseless merges and certainly without reparenting. You may be confusing reparenting with reverse integration (up the graph)?
Regards,
Bill Heys
VS ALM Ranger
|
|
|
|
|
wheys wrote:
fastboxster wrote:
For the reparenting issue, if a release more closely resembles a prior release instead of the stable build on main (as in the case of the interim release - which includes some bug fixes, and a select few features that are solid) it is convenient to branch
from the prior release (release 2.1 branches from release 2). However, if you are not redistributing release 2 (as in the case of a web app), but rather "locking" or archiving it, you need to reparent to main so you can merge bug fixes
back to the DEV branch. In order to do this you have to perform a baseless merge (although I wouldn't consider it baseless, as it starts with the same base). I think the reparenting feature should support this. The one time I was able to
do this using the UI to reparent version 2.2 (descendent of 2.1) back to main was after I installed the hotfix for the branch by label issue. So I presumed that the hotfix now allowed reparenting up the graph.
Doug
What you seem to be describing is a variation of either the Standard or Advanced branch plan. If you refer to the Rangers Branching Guidance 2010, you will note that in the Standard branch plan, there is a Servicing (or Service Pack) branch between the Main
branch and the Release branch. When the code in Main (for release 2) is stable and ready to release, you would branch Main to ServicePack (for release 2) and branch ServicePack to Release (for release 2). You would ship from the Release branch (for release
2) and lock it down (make it read-only for safekeeping).
Bill Heys
VS ALM Ranger
The issue in our case then is that Main is stable and ready for a future release (version 3.x), but one or more the dependent systems is not yet ready, so it will not go live for a while. Yet, we have some important and critical fixes and features
that can go. What I've done typically in this case is branch from the prior version branch (Release 2.2), performed an uncessary baseless merge to create the merge relationship with main, and then reparented so that Release 2.3 has a merge relationship
with Main. I've tried to branch from Main from the v2.2 label (or by using the date), and it does not work well (as TFS makes odd inferences on subsequent merges). We don't RI up the graph because we won't be updating the Release 2.2, nor 2.1 nor
2.0, as they are locked and the bugs in them will stay there forever. However, we will RI to main and then to DEV. We don't accumulate a bunch of fixes and put them on a floppy disk to distribute the patch. We only have one system live at
a time (as it is a web application). Building service packs does not fit the pardigm as I see it (although maybe you are just illustrating some similarities in the branching pattern). I'll try branching Main into a Release branch, then branching
new Release versions from it (by branching the active release and then renaming the child to the archived version) and it will avoid the baseless merge issue, however I still think it makes sense that you should be able to merge to any descendent or ancestor
instead of just immediate decendents and ancestors. I also think I won't like the outcome, as I like to keep the workspaces for each "go-live" active, so I could in theory go back to those releases if we discover major issues down the road.
|
|
|
|
|
wheys wrote:
fastboxster wrote:
So if changeset-based (or work-item based) merging is discouraged, then why does TFS support it? To me it feels like TFS is not fully supporting it because the merge engine isn't robust enough yet to support it, yet they know the feature is important.
To me it seems like an essential part of development for large projects. How would you handle this scenario?
Thanks,
Doug
We have not said, I don't believe, that the *tool*, TFS does not fully support changeset-based merging (cherry picking). There are many challenges one needs to understand before making cherry picking a standard merge approach.
Do you decide in advance that File01 and File02 are part of the same feature and should either be released together or not-released until both are ready?
Are the changes to File01 and File02 both attached to the same Work Item?
How do you ensure that all of the changesets involving both File01 and File02 are correctly merged (the problem of not merging enough).
- What happens if Changest #004 is not picked up in the merge?
- How do you prevent this problem?
- How do you detect this problem?
- How do you fix this problem?
How do you ensure that every time a change is checked in (and a new changeset is created) that it is properly associated to the correct work item?
- What happens if the developer fails to associate the change with a work item?
- What happens if the devloper associates the change with the wrong work item?
- How do you prevent this problem?
- How do you detect this problem?
- How do you fix this problem?
What happens, after you do this first cherry picking merge, if subsequent bug fixes or enhancements are made to file01 and / or file02?
- How do you ensure that this bug fix is picked up in the next merge?
- How do you avoid re-merging changesets that have already been merged?
- How do you avoid a merge that takes a stable (bug-free) component in the target branch and introduces a new bug because of an incomplete merge (merge too little) or invalid merge (merge too much).
What happens if you discover while testing file01 and file02 that there is a bug in file03 that needs to be resolved before you can release file01 and file02?
- How do you add this new bug to the release?
- How do you ensure that you do not merge too little? For example, is it possible to merge just the bug-fix changeset to file03 - without merging all the predecessors changes fo file03. Wouldn't this leave file03 in an unstable state?
I could continue, but I think the point I am making is that when you do cherry picking merges as a part of your regular develop/test/stabilize/release process you have to be much more careful and rely on your developers being much more careful all along
the way. The risk is that it is far easier to introduce bugs into the target branch when you rely on cherry picking rather than merging the latest version of a branch that has been stablized. I am not saying the tools (TFS) cannot or do not support it.
But to be clear, no tool will be capable of making sure you cherry pick the changes you want, and only the changes you want, and all of the changes you need to ensure the target branch has just the right changes (not too much and not too little).
The caution against cherry picking is more becuase of the challenges to the process than with the tools.
Regards,
Bill Heys
VS ALM Ranger
I agree it is a challange, but that is why we buy sophisticated software to help. As it is, I have to use Beyond Compare as well as TFPT to get the job done. We label our changesets with the enhancement or defect # and the
proposed release number (we go back and edit the comments once it is determined that it will go in the next release). I look at the changes and confirm that it is "compatible" with the release before it is merged in (this is called staging
and is part of Rational's UCM). Almost every regression error we get is due to TFS making the wrong merge decision and not even displaying the merge conflict dialog.
So are you advising that we wait until the build on Main is stable and all dependent systems are ready before we attempt to deploy anything? This makes a hard to hit target nearly impossible to hit (we have multiple teams, so it is already complex
as it is). We might not ever get anything out the door. Our stakeholders would prefer a pared-down release on regular intervals versus a deferred release. Do you plan to address "advanced web development" in your guide?
|
|
|
|
|
fastboxster wrote:
wheys wrote:
fastboxster wrote:
For the reparenting issue, if a release more closely resembles a prior release instead of the stable build on main (as in the case of the interim release - which includes some bug fixes, and a select few features that are solid) it is convenient to branch
from the prior release (release 2.1 branches from release 2). However, if you are not redistributing release 2 (as in the case of a web app), but rather "locking" or archiving it, you need to reparent to main so you can merge bug fixes
back to the DEV branch. In order to do this you have to perform a baseless merge (although I wouldn't consider it baseless, as it starts with the same base). I think the reparenting feature should support this. The one time I was able to
do this using the UI to reparent version 2.2 (descendent of 2.1) back to main was after I installed the hotfix for the branch by label issue. So I presumed that the hotfix now allowed reparenting up the graph.
Doug
What you seem to be describing is a variation of either the Standard or Advanced branch plan. If you refer to the Rangers Branching Guidance 2010, you will note that in the Standard branch plan, there is a Servicing (or Service Pack) branch between the Main
branch and the Release branch. When the code in Main (for release 2) is stable and ready to release, you would branch Main to ServicePack (for release 2) and branch ServicePack to Release (for release 2). You would ship from the Release branch (for release
2) and lock it down (make it read-only for safekeeping).
Bill Heys
VS ALM Ranger
Building service packs does not fit the pardigm as I see it (although maybe you are just illustrating some similarities in the branching pattern). I'll try branching Main into a Release branch, then branching new Release versions from it (by
branching the active release and then renaming the child to the archived version) and it will avoid the baseless merge issue, however I still think it makes sense that you should be able to merge to any descendent or ancestor instead of just immediate
decendents and ancestors. I also think I won't like the outcome, as I like to keep the workspaces for each "go-live" active, so I could in theory go back to those releases if we discover major issues down the road.
What I am calling a ServicePack could easily be called a Minor Release.
Why not consider this branching structure:
When Main is ready for a major release (Release 2.0):
- Branch Main to Servicing
- Branch Servicing to Release 2.0) and lock it down
- Servicing is now available for Release 2.1 (post Release 2.0) critical fixes and features.
When MinorRelease 2.1 is ready to ship:
- Branch Servicing to Release 2.1 and lock it down
- Servicing is now available for Release 2.2 (if necessary), and so forth.
At any point in time, you have a Release branch locked down with the major or minor released code, AND you have a Servicing branch for critical fixes and features post release.
Main, once Release 2.0 happens can be freed up for Release 3.0. Changes can be rolled up from the servicing branch to Main
You don't need reparenting. You simply need to avoid inverting the relationships between the Release branch and the New Release version (what I call servicing)
Rather than branch a new Release branch from a prior Release branch and then renaming and doing baseless merge and reparenting, you can avoid all of that by thinking of the Servicing branch as the new minor or major Release branch and the Release branch
as the current (minor or major) released version.
I think we are talking the same way, but using slightly different terms.
Regards,
Bill
|
|
|
|
|
So are you advising that we wait until the build on Main is stable and all dependent systems are ready before we attempt to deploy anything? This makes a hard to hit target nearly impossible to hit (we have multiple teams, so it is already complex as
it is). We might not ever get anything out the door. Our stakeholders would prefer a pared-down release on regular intervals versus a deferred release. Do you plan to address "advanced web development" in your guide?
No, I am certainly not advising holding up deploying *anything* until *everything* is ready. That is hardly agile, and I am a strong proponent of agile. I agree with your stakeholders that often regular incremental releases are much better than deferred
*big bang* releases. Many lives ago, I worked on mainframe applications in the Energy Utiliy (Gas and Electric) industry. My primary focus was architecting, designin, and building large-scale mainframe Customer Service Systems to support such old-fashioned
concepts as Meter Reading (using humans), Cycle Billing, Estimated Billing, Cancel Re-billing, etc.
These systems, back in those days (pre de-regulation) often took years to envision, design, build, stabilize and deploy. Several problems happened with those old *waterfall* approaches, where all of the requirements needed to be gathered up front (takes
six months), the architecture and design must be completed next (takes another six months), the code must be completed (takes a year) and then tested (takes forever). All sequentially in huge chunks of phases before the system could be deployed in one huge
*big bang* release. These companies would undertake a new CSS development only once every fifteen years (I am not generalizing, I have seen studies of the Energy utility industry).
Often the business had evolving requirements. But becuase the software developoment life cycle was waterfall and drawn out over two or three years, the customer was unable to get their evolving requirements incorporated into the new released system. What
do you tell them? Wait for the next release in fifteen years? How do you get a business to prioritize their requirements, when they KNOW that anything that is not top priority gets cut and they have to wait fifteen years for priority two requirements? But
I digress.
In theory, I think I could propose a branching structure (and process) - a banching strategy that would support your requirements. It does not NEED to be exclusively for *advanced web* development, but would, I suggest support any agile development/release
process that has similar characteristics:
- At any time there may be one, two, or more *released* versions of your product (application, system) which you need to support simultaneously. In your case you seem to have only one *released* version (be it Release 1.0, or Release 2.0, or Release 2.1).
You only have one *current* version that you need to deal with (unless I am misunderstanding something). For consistency sake let's call the current released version vCurrent. If vCurrent is Release 2.0 then Release 1.0 might be vCurrent -1, and the next release
being stabilized is vNext.
- At any time there may be one, two, or more feature teams developing new features. Any given feature team is working on a set of one or more features for a future release. The release may be vNext, or vNext+1 or vNext+2.
- Each Feature team will have one (or more) feature branches to enable the team to isolate their changes from changes made by other feature teams.
- Before a feature team can merge their code into the Main branch, it has to be stabilized *first* in the feature team branch, it has to pass QA quality gates, and it has to be *ready to release* or *ready to share*.
- When the code is *Ready to Release*, that means that the code will become part of the vNext release, and can be merged into the Main branch for stabilization and release.
- There may or may not be other feature teams. If there are multiple feature teams, they may or may not be working on the same release (vNext). By definition if you have a situation where one team is *Ready for Release* and another team is not, then you are
working on development for vNext (Ready for Release) and vNext + 1 or even vNext + n (NOT ready for Release yet).
- At any time that you want to Relase a new major or minor version, you select which feature teams are *Ready for Release* and which are not. You merge, one at a time, the latest version of the feature branch for each of the feature teams that will be part
of the vNext release.
- If a team is *Not Ready for Release* then you do NOT merge their code into the Main branch since they are not ready. They will have their features mereged into Main only at such time as their feature is ready for release and is determined to be part
of the vNext release (from Main).
So all of this boils down to a few key questions:
- How many releases do you need to support? I assume vCurrent, but also vCurrent -1? or vCurrent - 2.
- Do you issue hotfixes to any of the supported releases?
- Do you issue Service Packs to any of the supported releases?
- How many development (feature teams) do you have?
- Are these feature development teams all working on the next release (vNext) or are thy working on multiple releases in parallel (vNext, vNext +1, vNext +2)
- How often do you do a major release?
- How often do you do a minor release?
Finally the approach:
Think of the development side of the branching strategy separately from the release side:
- All releases are stabilized in Main and branched when shipped to one (or more) branches on the *release* side
- All releases are developed in one or more branches on the *development* side.
- Bugs that are identified during stabilization of a release (but before the release is shipped) are fixed on the development side
- Bugs that are identified after a release ships are fixed on the release side.
- You may or not need a read-only branch for safe keeping
- You may or may not need safekeeping branches for each hotfix or service pack
- If you do NOT issue hotfixes or service packs, consider the basic branch plan (on the release side)
- If you issue hot fixes (but not service packs) consider the standard branch plan (on the release side)
- If you issue both hot fixes and Service packs to a released version, consider the advanced plan (on the release side)
- If you have ony one version under development (vNext), and only one feature team, you have a simple branching structure on the *development* side (Main + Development)
- If you need feature team isolation (either for teams working on the same release, or for teams working in parallel on multiple future releases - add complexity to the *developmen* side - by adding more feature branches.
- Unless you can make a strong case for why you need an extra *isolation* branch layer, between all (or some) of the feature branches and the main branch, do not add it.
- Integrate features (or sets of features from a single feature branch) into main - one at a time.
- After integrating a feature branch into Main, integrate Main into all of the other feature branches - daily
- Keep main as stable as possilble - it is used for QA stabilization of vNext and should not have vNext +1 or vNext +2 code until vNext has shipped.
- Wherever possible, branch and merge from the latest version of a branch rather than doing cherry picking
- Consider an integration branch layer between Main and the Feature branches:
- When you are working on multiple future releases in parallel (vNext, vNext + 1, vNext +2) and for any version you have multiple feature teams working in parallel that may need to share or integrate their work. So for example, while Main is used
to stabilize vNext release, you might have an integration branch (between Main and the vNext+1 branches) so that the vNext +1 can start doing integration testing while Main is still dedicated for vNext stabilization
- When you have multiple feature teams working on the same release - and you want to do integration testing and sharing code between teams, but you do not want to destabilize the Main branch and you do not want ot interfere with forward progress in the feature
teams while integration is being tested (code velocity). Consider automated testing of builds in the development branches as a preferred way to improve code velocity.
- Code (for development and bug fixing during development) should be checked into development branches (or feature branches) and tested before merging with Main
- Code should not be checked into Main directly. Code can be merged into main once; tested.
- Code for post release bug fixing is checked into the servicing branch (service pack or hotfix) for a release. But the release branch is locked down when released (shipped) and made read-only
Thoughts?
Bill Heys
VS ALM Ranger
|
|
|
|
|
Thanks Bill. There are a lot of good suggestions there. I'm not sure we are at the point where we need to introduce feature branches on our project just yet, however if we had known that some of the features were not going to be ready for release,
it might have been nice to have the changesets all on one branch. I still hope the "advanced" features for TFS are extended so that when we need to do something, it doesn't feel like we are cheating to get it done. I'll spend some time
and look over your suggestions to see what all we can implements. Thanks!
|
|
|
|
|
I suggest that if you haven't already downloaded Ranger Branching Guidance 2010, you might want to.
This is the latest version of the Rangers Branching Guidance. It replaces Branching Guidance 2.0 and is applicable to TFS 2008 as well as TFS 2010.
In other words, the *2010* in the Guidance title does not mean you have to use TFS 2010 with this guidance.
Regards,,
Bill Heys
VS ALM Ranger
|
|
|
|
|
Yes, I've read it. Thanks.
|
|
|
Feb 28 2011 at 9:17 AM
Edited Feb 28 2011 at 12:05 PM
|
Having come to TFS from a background in Subversion, Git and Mercurial, and also having experimented with Perforce, I was absolutely flabbergasted to hear that TFS treats merges between sibling branches as baseless.
I see no technical reason whatsoever why this should still be the case in 2011. It is totally incorrect to say that sibling branches have no common origin: the common origin for a sibling-sibling merge is the revision in the parent from which the first branch
was created. It should also be possible to find a common origin for branches that are fourth cousin twice removed by recursively searching back through the branches. Git and Mercurial have been able to do this from Day One. Perforce has been able to do this
since 2004 -- before development on Git and Mercurial even started.
I also see no convincing ALM reason whatsoever either why this should be the case. The only reason I've been given for it is that you shouldn't be merging from, say, a feature branch back directly into your production branch. While I agree wholeheartedly
with this policy, there are better ways to fix the problem e.g. security restrictions or policies on code lines that require change management, and the concept of "baseless merges" just causes a whole lot of collateral damage.
For example, here's a scenario where you'd want to merge sibling branches together. Alice creates a feature branch off of your live branch instead of off your development branch by mistake. She commits several revisions then tries to merge back into the
development branch -- where she's supposed to -- and finds that she has to do it the hard way. What's all that about? If she were using Git, this would be a non-issue.
A well designed system should forgive mistakes like this, not punish them.
Here's another scenario. You have three different features developed on separate branches. You want to create a temporary branch to showcase them to your stakeholders, who may want to sign off on features A and B but not C, so you can then cherry-pick only
those features that get signed off into your production branch. Easy with a DVCS. All but impossible with TFS thanks to baseless merges.
Finally, the statement "A huge risk with doing a sibling->sibling merge is that future siblings (which branch from the same parent) won't have the change since it was never RI'd back to the parent branch" is incorrect. Any changes merged from Alice's
branch to Bob's branch will be RI'd back to the parent branch implicitly along with all of Bob's other changes. If you draw your revision history across your branches as a directed acyclic graph and trace back what was included, you'll see
exactly what I mean.
All in all, I find it very hard to believe that this limitation really is by design. If it were, it would be configurable by policy, not enforced right across the board.
|
|
|
|
|
You are entitled to your opinion, even though I disagree with most of your conclusions.
One question: Who is Bob? Is he the fourth cousin twice removed?
|
|
|
Feb 28 2011 at 2:08 PM
Edited Feb 28 2011 at 2:09 PM
|
I will respond shortly with more detailed answers (and questions)
Regards,
Bill Heys
|
|
|
Feb 28 2011 at 2:08 PM
Edited Feb 28 2011 at 2:10 PM
|
|
|
|
|
|
I believe Perforce has similar issues and approaches with merging sibling branches:
Read:
http://kb.perforce.com/article/9/merging-changes-between-unrelated-codelines
Some key points: "
Consider the following situation. You have two codeline paths B and
C, each of which was originally branched from the same path,
A. The files in paths B and
C are therefore not directly related to each other by branching, although they do share a common ancestor:"
Release 2002.2 to 2003.2
When you attempt to integrate between source and target paths, no files are opened for integrate unless previous source-to-target history exists. By default, Perforce does not open a file for integrate unless it can find a base revision to use for a 3-way
merge. Base revisions are chosen according to integration history, so when there is no integration history Perforce detects a "baseless" merge. As of Release 99.2,
baseless merges are not permitted
Release 2004.2 (or later)
Nothing extra need be done as p4 integrate for release 2004.2 and later always considers indirect integrations through intermediate branches when determining that files are related and what changes need to be integrated. The direct/indirect
option in branch specifications has been removed as all integrations are considered indirect. Also,
p4 integrate might select a base for merge resolution from a common ancestor which is neither the source nor the target file.
The reason why we discourage baseless merges is, in part, because they generally generate more merge conflicts, which are more time consuming to resolve:
- Conflicts cannot be auto-merged
- Deletes are not propagated
However, once you do a baseless merge between two unrelated branches, a merge history now exists. Future merges between these two branches in TFS can be done through the UI without doing baseless merges. In other words, as with other tools, TFS recognizes
that there is no merge basis already existing between two branches. The tool essentially has to go back to the common ancestor of each file in the source and target branches. It will then make you resolve all conflicts manually between the two versions.
Regards,
Bill Heys
|
|
|
|
|
Thanks for your response Bill. I may have misunderstood the Perforce documentation here, but just to make sure I'll take another look at it and compare it side-by-side with TFS this evening on a simple sibling branch scenario and report back.
|
|
|
Feb 28 2011 at 3:51 PM
Edited Feb 28 2011 at 3:52 PM
|
JammyCakes:
In your favorite tool, create the following scenario:
- Create a Main branch, add a sample application (for example, a class library) to the Main branch
- Branch Main -> Dev-A
- Branch Main -> Dev-B
- Add Main.cs, ClassA.cs, and ClassB.cs to the solution in the MAIN branch
- Change Main.Cs, ClassA.cs and ClassB.cs in the MAIN branch
- Add ClassA to the DevA branch (we now have two different files named ClassA.cs - one in the Dev-A branch and one in Main)
- Change ClassA in the DevA branch
- Add Main.Cs in the DevA branch (we now have two differenct files named Main.cs)
- In the Dev-A branch, rename Main.cs to MainRenamed.cs
- In the Dev-A branch add a new Main.Cs
- In the Dev-A branch, make changes to Main.cs and MainRenamed.cs
- In the Dev-B branch, add Main.cs and ClassB.cs we now have four versions of Main.cs (on in Main, two in Dev-A and one in Dev-B
- In the Dev-B branch, delete ClassB.cs
- In the Dev-B branch, change ClassA.cs
- In the Dev-B branch, rename ClassA.cs to ClassB.cs
- In the Dev-B branch, add a new ClassA.cs
Now merege:
- Now do a merge between the two sibling branches (DEV-A and DEV-B)
- Next merge Dev-B to Dev-A (since there is now a merge relationship between these two branches, this will not be a baseless merge.
- Next merge Dev-A to Main
- Next merge Dev-B to Main
- Next merge Main to Dev-A
- Next Merge Main to Dev-B
Continue this until all three branches are in sync and have the changes you want in each branch.
For Perforce:
- Was the tool able to do this without a baseless merge?
- Were there any merge conflicts resulting from this merge of sibling branches?
- How did you resolve the fact that a class in Main was deleted or renamed in Dev-A before the merge and changes were made to both files
- How did you resolve the fact that conflicting classes with the same name were added to both branches - you want to keep both classes
- Were any of the merge conflicts resolved automatically by the tool?
- How many merge conflicts did you resolve manually?
- How did you resolve the renaming, deleting, readd conflicts?
- Tell me which version of each class Main.cs, ClassA, ClassB, and MainRename ended up in Dev-B after the merge.
For Subversion same eight questions.
For Git same eight questions
For Mercurial same eight questions.
Regards,
Bill Heys
VS ALM Ranger
|
|
|
|
|
Interesting blog on what TFS CAN do that Mercurial CANNOT do:
You cannot do this [Merging by changeset, or cherry picking] in Mercurial, at least, not with a "merge" operation. The only way to accomplish the same type of thing would be to create a patch out of NewBranch and apply it to Source using the hg export and
hg import commands
http://kevin-berridge.blogspot.com/2009/04/what-mercurial-cant-do-merge-by.html
Regards,
Bill Heys
VS ALM Ranger
|
|
|
|
|
Interesting blog on Merge vs Rebase in GIT:
http://gitguru.com/2009/02/03/rebase-v-merge-in-git/
Things are not so simple in any of these tools. Some do branching, some do repository cloning. All are challenged with merge conflicts. Your results may vary in GIT depending on whether you merge or rebase.
There is NOT any reason to be "absolutely flabbergasted" by HOW TFS deals with merging two branches that are siblings (or fourth cousins twice removed). The bottom line, as I think I demonstrated in my scenario, is that it is challenging to resolve
merge conflicts even when you are doing normal parent/child merging. But when you are merging hundreds of changes across two sibling branches where there are conflicting changes between them and between each of them and their common parent and you need to
figure out how to resolve them, it can be very time consuming to unravel the individual developer's intent. Iin some cases you may want to replace a change in Main with a change in the Dev Branch during a reverse integration. In some cases you may want the
opposite. Sometimes you have two files with the same name in different branches and you really need both files and have to rename one of them (and fix the build). You create a file, Bob deletes it, Alice re-adds it! Who wins? I think you wrongly focus on the
work Baseless in TFS, and greatly simplify the challenges of doing similar functionality in your other *favorite* tools.
Even the TFS team will admit that the TFS merge tool is not the best of breed. They will be working to make merge conflict better in the future. In the meantime, there are third party tools you can plug into TFS (for example, Kdiff, Araxis, or Source Gear's
DiffMerge). I concede that TFS is not the perfect tool in all scenarios, but as an ALM platform integrated into the Best-of-breed IDE (Visual Studio 2010) it is a compelling story.
Regards,
Bill Heys
VS ALM Ranger
|
|
|
|
|
Interesting blog on Merge vs Rebase in GIT:
http://gitguru.com/2009/02/03/rebase-v-merge-in-git/
Things are not so simple in any of these tools. Some do branching, some do repository cloning. All are challenged with merge conflicts. Your results may vary in GIT depending on whether you merge or rebase.
There is NOT any reason to be "absolutely flabbergasted" by HOW TFS deals with merging two branches that are siblings (or fourth cousins twice removed). The bottom line, as I think I demonstrated in my scenario, is that it is challenging to resolve
merge conflicts even when you are doing normal parent/child merging. But when you are merging hundreds of changes across two sibling branches where there are conflicting changes between them and between each of them and their common parent and you need to
figure out how to resolve them, it can be very time consuming to unravel the individual developer's intent. Iin some cases you may want to replace a change in Main with a change in the Dev Branch during a reverse integration. In some cases you may want the
opposite. Sometimes you have two files with the same name in different branches and you really need both files and have to rename one of them (and fix the build). You create a file, Bob deletes it, Alice re-adds it! Who wins? I think you wrongly focus on the
work Baseless in TFS, and greatly simplify the challenges of doing similar functionality in your other *favorite* tools.
Even the TFS team will admit that the TFS merge tool is not the best of breed. They will be working to make merge conflict better in the future. In the meantime, there are third party tools you can plug into TFS (for example, Kdiff, Araxis, or Source Gear's
DiffMerge). I concede that TFS is not the perfect tool in all scenarios, but as an ALM platform integrated into the Best-of-breed IDE (Visual Studio 2010) it is a compelling story.
Regards,
Bill Heys
VS ALM Ranger
|
|
|
Feb 28 2011 at 11:45 PM
Edited Mar 1 2011 at 12:19 AM
|
@Bill,
Your exercise is interesting and probably worth doing, but although point 14 says "In the Dev-B branch, change ClassA.cs", there is no ClassA in the Dev-B branch at this point. Perhaps you could clarify?
In the meantime, however, I can tell you that:
- Git, Mercurial and Perforce will all quite happily merge from Dev-A to Dev-B even though they are not in a parent/child relationship, and the merges will NOT be baseless. There may be some conflicts, but that is only to be expected. Certainly the ones that
you would expect to be auto-resolved will be auto-resolved.
- Git and Mercurial both support merge-over-rename, so the changes to Main.cs in Dev-B will be correctly merged into MainRenamed.cs in Dev-A. I'm not sure about Perforce.
- Subversion will probably struggle with this scenario. Subversion's merge algorithms have problems of their own, but baselessness of sibling branches isn't one of them.
Having said that, I think it's a bit of a red herring. This is a very contrived scenario and one that doesn't happen a lot in the real world, unless you have real communication problems.
In practice, people have found over the past few years that fluent, frequent branching and merging poses no more of a risk to the integrity of your project than any other way of combining changes from different developers, provided that
you have tooling that supports it. Furthermore, merging between branches can be automated to a much greater extent, far more reliably than you'd expect. This is the experience of thousands of teams working on a wide variety of projects, some
of which are widely deployed in systems that could kill people if they go wrong -- most notably, the Linux kernel. Yes, you get conflicts, no, it doesn't always work out flawlessly, but it isn't as scary as you'd expect.
My intent here is merely to answer the original question posted by this thread:
should TFS support three-way merges between branches not in a direct parent/child relationship? Personally, my answer here is
yes, absolutely, and why hasn't this been done already? As I said, I don't see any
technical reason why merges between sibling branches should be baseless, so the only justification here would be from an ALM perspective. Again, here, I don't quite "get it" -- making merges baseless just because they're not in a direct parent/child
relationship means just making the whole process harder, which is the exact opposite of what a "tool" is supposed to do. If there is a valid reason for restricting sibling merges, why not make it configurable by policy or security instead? That would be a
far better solution, since then teams that need it and are disciplined enough not to do stupid things could take advantage of it, while more paranoid managers could restrict it if need be.
|
|
|
|
|
@jammycakes
There is not much reason for me to continue this discussion. I disagree with your conclusion that Git, Mercurial, and Perforce will merge sibling branches (that are not in a parent-child relationship) with substantially different effort and results than
TFS. I offered let you show me how sibling merges work in ANY of the other tools, but you would prefer to *interpret* the documentation instead. So there is not much point to engaging in hypothetical debating.
I am happy to show you the steps I have gone through and the merge conflicts that result. TFS is perfectly able to do three-way merges between sibling branches. The fact that it is a baseless merges to start with, mostly means that the tool will not
automerge the conflicts. My primary objection to baseless merges is that too often people build their entire process around baseless merges rather than follow a better branch and merge practice where merges are routinely done between parent and child and baseless
merges are only used in certain circumstances. For example, if you want to reparent a branch, to a different branch, you start by doing a baseless merge between the child and its new parent branch. Then you can reparent it.
The example I posed was designed to illustrate, in a concise way, how conflicts can arise when changes are made in isolation in three branches (parent, child, child). It is not unusual for conflicting changes to be made to the same file in two different
branches. It is also not unusual for files to be deleted and new files added with the same name. Or for files to be renamed. I see support cases all the time where customers are doing this without understanding the consequences. Feel free to trivialize my
scenario and to call it a red herring.
It would be enlightening for you, in my view, if you proved to yourself with a side-by-side comparison, that there is not enough difference from one tool to another to get concerned. I am not interested in engaging in a religious battle over whether one
tool does baseless merges and another tool does merges in a different way. I am more interested in helping people understand and use TFS not engaging in a battle I cannot win.
You can have the last word. I have made all the points I intend to make without concrete comparisons that prove your contentions.
Regards,
Bill Heys
VS ALM Ranger
|
|
|
|
|
I missed one step in my scenario, following step 12 add a new step 12a. Add ClassA.cs to the Dev-B branch, sorry.
|
|
|
|
|
From a post by Buck Hodges:
Starting with TFS 2010 SP1, there are two improvements to how baseless merges work: base file version and handling deleted files.
First is that if you specify a starting range for a baseless merge, we will now use that changeset as the base in the three-way content merge. That results in a vastly improved experience in merging file content for a baseless merge. For example, tf merge
/baseless /v:1234~1234 $/ProjX/foo $/AcmeV2/foo or tf merge /v:1234~T $/ProjX/foo $/AcmeV2/foo.
The second is the handling of deletions. Before the change, items that are deleted in the source branch were not included in the baseless merge. That meant that if you had deleted obsolete files as part of your changes they would not get deleted in the target
branch when doing a baseless merge. After the change, if a path is deleted in the source the corresponding path in the target will have a merge,delete conflict. Also, if a file is not deleted in the source but is deleted in the target, the target will get
a merge,undelete conflict. The result is that you get a higher fidelity result in the target branch. This was made possible by the
changes in TFS 2010 where merge lines up the items by path rather than by item ID
http://blogs.msdn.com/b/buckh/archive/2011/02/06/improvements-to-baseless-merge-in-tfs-2010-sp1.aspx
Regards,
Bill Heys
VS ALM Ranger
|
|
|
Mar 2 2011 at 9:33 PM
Edited Mar 2 2011 at 10:10 PM
|
Well that's a step in the right direction. However, I can confirm that I have carried out merges between sibling branches in Perforce, Subversion, Git and Mercurial, and none of those tools treat these merges as baseless. It is certainly not the case that
I am, as you say, "only interpreting the documentation." The bullet points I made in my post above are based on experiments that I have actually carried out using these tools to verify what happens.
I will carry out your experiment at some stage -- it's pretty interesting and I'd like to know how all the tools cope with it, but I haven't had time yet, besides which I needed that extra step that you missed out in order to do so.
(Pedant's note: strictly speaking, in Git and Mercurial, the concept of "sibling branches" is a bit meaningless here since these tools implement branching using a directed acyclic graph within your project history, in which branch parentage and naming
is considered to be "for information only" and plays no part in the merge algorithms themselves. However, these tools are able to find a common origin even for fairly complex branch topologies, and merges with them are certainly not baseless.)
Bill, I'm not trying to get into a religious war here about one tool being better than another. I'm just saying that it is technically possible to treat merges between indirectly related branches as
a priori non-baseless; that even if you do agree that branching and merging is hard and risky (which is a pretty dubious assertion these days), treating these merges as baseless just makes the situation worse; and that whatever beneficial effects it
may have in discouraging long-running feature branches or inappropriate integrations, it causes a lot of collateral damage by making certain genuinely useful workflows unduly difficult and risky. The original poster asked the question, should this be fixed,
and I just want to make the case that it should. I would also like to know what the plans for future versions of TFS are in this respect.
Finally, as I've suggested a couple of times before, if you really think there is a compelling case for making indirectly related merges baseless, why not have this set as some kind of policy instead? That way, more advanced teams would be able to take advantage
of more complex branching and merging strategies if they wished to do so.
|
|
|
Mar 2 2011 at 11:01 PM
Edited Mar 2 2011 at 11:12 PM
|
One other thing.
wheys wrote:
The example I posed was designed to illustrate, in a concise way, how conflicts can arise when changes are made in isolation in three branches (parent, child, child). It is not unusual for conflicting changes to be made to the same file in two different
branches. It is also not unusual for files to be deleted and new files added with the same name. Or for files to be renamed. I see support cases all the time where customers are doing this without understanding the consequences. Feel free to trivialize my
scenario and to call it a red herring.
I stand by what I said: this is a red herring. However, this does not mean to say I am trivialising it: it is a very real problem. I call it a red herring because it is not specific to branching and merging, let alone to sibling-sibling merges. It can crop
up just as easily in trunk-based development, for instance, if I rename a file then commit, and someone else in the meantime edits the same file then tries to commit on the same branch. To suggest that this problem is specific to branching and merging, or
to sibling-sibling branches, is simply incorrect.
In fact, in trunk-based development, or shared branches, the risk is just as great. In these cases, developers often tend to delay checking in, in order to avoid breaking the build, and gated check-ins tied to strict build policies just exacerbate the situation.
Two separate two-week tasks that have been shelved regularly in the meantime carry exactly the same risks here as the same two-week tasks carried out on feature branches with intermediate commits. In fact, sibling-sibling merges between the feature branches
would lessen the risks of thorny conflicts here since they could be integrated with each other more frequently if necessary.
|
|
|
|
|
~
|
|
|
|
|
wheys wrote:
You can have the last word. I have made all the points I intend to make without concrete comparisons that prove your contentions
~
|
|
|
Mar 3 2011 at 12:13 AM
Edited Mar 3 2011 at 12:47 AM
|
OK here's what I did for starters. This is the simplest, basic, merging 101 situation between sibling branches. Get this wrong and there's no point even looking at anything else.
- Create a new project and check in to the Main branch.
- Create a file called test.txt containing the International Phonetic Alphabet. (Alpha, Bravo, Charlie, Delta, etc). Check it in.
- Branch from Main to Dev-a. In the case of Git and Mercurial, create a clone of the Main repository called Dev-a.
- Branch likewise from Main to Dev-b.
- In Dev-a:
- Delete "Bravo"
- Change "Juliet" to read "Juliet Capulet"
- Add "Nonomumu" after "Mike" and before "November"
- In Dev-b:
- Delete "Golf"
- Change "Romeo" to read "Romeo Montague"
- Add "Yesterday" after "Yankee"
- Merge from Dev-a to Dev-b, using whatever auto-resolve features the tools provide where possible.
Subversion, Git, Mercurial and Perforce all give the following results from a merge carried out through through their respective GUI tools:
Alpha
Charlie
Delta
Echo
Foxtrot
Hotel
India
Juliet Capulet
Kilo
Lima
Mike
Nonomumu
November
Oscar
Papa
Quebec
Romeo Montague
Sierra
Tango
Uniform
Victor
Whiskey
X-ray
Yankee
Yesterday
Zulu
These are the correct, expected results from such a merge, as I am sure we would all agree. All four tools can automate the process flawlessly if asked to.
Team Foundation Server refuses to carry out this merge through Visual Studio, requiring me instead to perform a baseless merge through the command line which reports conflicts which can not be auto-resolved. Plugging in a 3-way merge tool (Perforce Merge)
shows that it is providing the following (presumably "guessed") base for the merge:
Alpha
Charlie
Delta
Echo
Foxtrot
Hotel
India
Kilo
Lima
Mike
November
Oscar
Papa
Quebec
Sierra
Tango
Uniform
Victor
Whiskey
X-ray
Yankee
Zulu
This is incorrect: "Bravo" and "Golf" are missing and there are spurious blank lines where other edits were made. It appears to me (repeating the merge using the TFS built in merge tool, just to make sure it wasn't something to do with Perforce Merge) that
TFS is treating line-by-line differences between the two sides of a merge (e.g. Juliet <-> Juliet Capulet) as an insertion on both sides, which is incorrect, and additions or deletions as edits from a blank line on both sides, which is also incorrect.
|
|
|
|
|
wheys wrote:
wheys wrote:
You can have the last word. I have made all the points I intend to make without concrete comparisons that prove your contentions
~
|
|
|
Mar 3 2011 at 12:43 AM
Edited Mar 3 2011 at 12:55 AM
|
~
|
|
|
Mar 3 2011 at 11:21 AM
Edited Mar 3 2011 at 12:59 PM
|
I have given you concrete comparisons sufficient to prove my contentions.
Now I want a convincing answer to these questions:
- Why are merges between sibling branches baseless in TFS when none of the alternatives have this limitation?
- If it is design, why should it apply across the board and not be controlled by policy?
- If it is not by design, will it be fixed in a future version of TFS?
|
|
|
|
|
wheys wrote:
wheys wrote:
wheys wrote:
You can have the last word. I have made all the points I intend to make.
|
|
|
|
|
Whenever you get merge conflicts that cannot be resolved automatically, the merge confilct resolution dialog lets you review the conflicts and *choose* the appropriate changes to appear in the resulting merge files.
Obviously, when you have no idea how to do this you will probably end up with incorrect results.
For example, when I merge two files that have conflicting changes made on two branches, I can choose to only accept changes made in the source branch version of the file. I would get results like this:
Alpha
Charlie
Delta
Echo
Foxtrot
Golf
Hotel
India
Juliet Capulet
Kilo
Lima
Mike
Nonomumu
November
Oscar
Papa
Quebec
Romeo
Sierra
Tango
Uniform
Victor
Whiskey
X-ray
Yankee
Zulu
Or I could choose to take only the changes from the target branch version of the file, and would get results like this:
Alpha
Bravo
Charlie
Delta
Echo
Foxtrot
Hotel
India
Juliet
Kilo
Lima
Mike
November
Oscar
Papa
Quebec
Romeo Montague
Sierra
Tango
Uniform
Victor
Whiskey
X-ray
Yankee
Yesterday
Zulu
Or, if as a person knowledgable about the changes made to both the source and target, I could pick from either the source or the target and get results like this:
Alpha
Charlie
Delta
Echo
Foxtrot
Golf
Hotel
India
Juliet Capulet
Kilo
Lima
Mike
Nonomumu
November
Oscar
Papa
Quebec
Romeo Montague
Sierra
Tango
Uniform
Victor
Whiskey
X-ray
Yankee
Yesterday
Zulu
I would NOT want a tool neccessarily to always automerge or always make the decision FOR ME as to:
whether the changes made in the source branch were to always override the changes in the target branch,
or whether the changes made in the target branch would always override the changes in the source branch.
For example, developer A deleted Bravo, and developer B did not. Maybe when I resolve the conflict I want Bravo in the resulting file. Your automerge gives me the WRONG result.
Likewise Developer A did not change Romeo but Developer B changed Romeo to Romeo Montague. When I resolve the conflict, I can choose to take the change from the source version OR the target version OR both (on a conflict by conflict basis)
I am not forced to take All or Nothing.
JammyCakes It is clear from your arguments here and on on the other discussion forums that you are more interested in argument than explanation. It is also clear from your tweets that you are more interested in sniping and attacking TFS
not trying to understand how TFS works.
I am adding this post to clarify your intentionally misleading, incorrect, and superficial comparisons of TFS with other tools that you obviously prefer. I am not going to attempt to convince you that TFS is better than your favorite tool.
But I have an obligation to other people reading the guidance and posts on this forum to NOT let your intentional misinformation go unanswered.
|
|
|
Mar 5 2011 at 12:06 PM
Edited Mar 5 2011 at 12:44 PM
|
Bill,
OK, hands in the air, maybe I have been venting steam at TFS a bit too loudly. If I've caused any offence, I apologise.
However, I reject your accusations that my comparisons are intentionally misleading, superficial and incorrect. My criticisms of TFS may have been harsh, but I have generally tried to limit them to technical ones, to ensure that objective statements
of fact are verifiable, and I would certainly not publicly accuse anyone of deliberate, intentional wrongdoing. When I see someone saying something that I consider to be wrong, I will say so, but I will assume that it is an honest misunderstanding rather than
deliberate misinformation unless there is clear, unambiguous evidence to the contrary. Admittedly, one of my tweets may be a little bit questionable in that respect, but that was because I was frustrated that the only responses I was getting to my
questions were "I have made all the points that I want to make," when the points that you have made did not answer my questions to my satisfaction but only raised other questions.
I don't want to be convinced that TFS is better than X. However, I do want to know why it behaves the way it does, and why exactly merges between sibling branches are baseless. I also want to see it improved, since in many cases, we have no choice in the
matter about whether to use TFS or not. I fail to see any convincing reason from either a technical or an ALM perspective why merges between sibling branches should be baseless, that is all, and I just want to know, if it is by design as you say, why. If
there is a valid reason for it, I will accept it, but at the moment I just don't "get it."
Your point about automatic versus manual merges is a valid one, where I believe TFS strikes the right balance. In fact, this particularly impressed me about TFS when I encountered it, since at the time, no other source control tool that I had used offered
me this facility, instead favouring a fully automated approach. Since then, however, Mercurial has adopted a similar approach in TortoiseHg 2.0. In actual fact, while fully automatic merges are pretty scary if you're not used to them, in practice, they usually
work surprisingly well, since any problems that they don't pick up on are usually detected either at compile time or by unit tests, and problems that make their way into production are no more common than bugs introduced by any other route. However, it
is equally possible to encounter similar problems in trunk-based development, with Visual SourceSafe-style file locking, or even with everyone editing source code over a network share, if two developers make changes to different files at the same time.
This is the problem that I have with the scenario you have outlined. It highlights a whole lot of issues that are genuine concerns but that are not specific to branching and merging, let alone merges between sibling branches, which is the question at hand.
Now, the nature of the scenario that I outlined. As I said, automatic versus manual merges are not the point. The point of my scenario was to prove that an
a priori three-way merge, between sibling branches is technically possible. Whether such a merge is carried out automatically or manually is a moot point, but when it is carried out manually, I want to see the common origin represented accurately in
my merge tool, not as some kind of a guess. I want to know, for instance, that Bravo was removed from Dev-a rather than being added to Dev-b. I certainly would not want to see blank lines that do not exist in either Dev-a, Dev-b or the common origin to start
with. I am sure you would agree.
So, I repeat my questions. If there is a valid reason why merges between sibling branches in TFS should be baseless, what is it? If it is merely a technical limitation, what plans are there to address it?
Until I get satisfactory answers to these questions, there is no point in continuing this discussion.
|
|
|
Mar 5 2011 at 12:31 PM
Edited Mar 5 2011 at 12:36 PM
|
jammycakes wrote:
As I said, automatic versus manual merges are not the point. The point of my scenario was to prove that an
a priori three-way merge, between sibling branches is technically possible. Whether such a merge is carried out automatically or manually is a moot point, but when it is carried out manually, I want to see the common origin represented accurately in
my merge tool, not as some kind of a guess. I want to know, for instance, that Bravo was removed from Dev-a rather than being added to Dev-b. I certainly would not want to see blank lines that do not exist in either Dev-a, Dev-b or the common origin to start
with. I am sure you would agree.
There is little you have said that I agree with. I would prefer you characterize your opinions as your opinions and refrain from assuming that I agree with ANYTHING you say. Once again you trivialize the strengths of my points of comparison and choose to
focus only on areas where you believe other tools give YOU the outcome that YOU prefer.
What I do agree with is there is no point in continuing this discussion. My goal here is to help TFS users learn and use the product more effectively. My goal is NOT to engage in endless debate with someone who clearly wants primarily to snipe TFS and promote
other products over TFS. That is NOT the purpose of this forum. Take your sniping back to your personal Tweets.
|
|
|
Mar 5 2011 at 1:02 PM
Edited Mar 5 2011 at 1:04 PM
|
Bill,
I will be satisfied with answers to the questions posed by this thread. That is all I ask for.
Once again, if I have been unjustifiably harsh, I apologise. If it becomes evident that I have made any incorrect or misleading statements of fact that need to be retracted or qualified, I will do so. If there is a more appropriate place to get answers to
these questions, please advise.
|
|
|
|
|
I will monitor your tweets to see if there is ANY point in continuing the dialog privately.
|
|
|
Oct 14 2011 at 9:56 AM
Edited Oct 14 2011 at 9:58 AM
|
http://img2.moonbuggy.org/imgstore/grandmother-handbag-fight.gif
|
|