Return value of Workspace.Merge()  
Author Message

PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top

I'm building an app using TFVC client API to do the following:

1. merge changes in a given changeset from branch-demo to branch-1.0
2. check in the pending merges in branch-1.0

here is the snippet of code:

VersionSpec ver = new ChangesetVersionSpec(cs.ChangesetId);
GetStatus gs = wsp.Merge(demoPath, targetPath, ver, ver, LockLevel.None, RecursionType.Full, MergeOptions.ForceMerge);

Now the problem is how to find out the pending changes resulting from the Merge method call
I thought it would be convenient to include a PendingChange[] as part of the returned GetStatus, no

Now i guess a rather cumbersome alternative is to do something like this:

String[] items = new String[cs.Changes.Length];
idx = 0;
foreach (Change ch in
  items[idx++] = GetItemInTargetBranch(ch.Item.ServerItem); //to be implemented
PendingChange[] pends = wsp.GetPendingChanges(items, RecursionType.None);

I haven't figured out a neat way to implement the GetItemInTargetBranch() function yet, or maybe there is a better way

Note that i can't simply call PendingChange[] pends = wsp.GetPendingChanges(targetPath, RecursionType.Full); because this app is supposed to be concurrently used by multiple users, so the above call could return pending changes from other developers.


Visual Studio Team System22  
Richard Berg MSFT

PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top

I don't know the exact details behind the GetStatus[] vs PendingChange[] API design. One good reason you shouldn't query for pending changes until later is that the result will vary greatly depending on how you resolve the merge's conflicts. For instance, returning the pending changes immediately after merge would artificially hide any renames or undeletes or parallel edits (since those always throw conflicts) -- each would show up with a misleading "merge" changetype instead of "merge, rename" etc.

There's an overload of GetPendingChanges that allows you to filter by user. Hopefully that eliminates the need for your workaround.

The other option is to register a handler for the Getting, NewPendingChange, and Merging events. That's what 'tf merge' uses to generate its output.

By the way, the GetItemInTargetBranch functionality you're looking for is very very tricky to get right. If you do need this for some reason, I'd highly recommend letting the server do it. Use QueryMergesWithDetails if the target has already been committed, or Merge with the /preview option if not.


PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top


I recently have attempted to write a short primer on merge, hopefully that may be of use to you.

Cheers, Eugene


PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top

thanks for the feedback, Richard, it gave me some perspective on how involved and messy this seemingly simple task could get with the currently TF client api.

1) re "GetPendingChanges that allows you to filter by user":
how does that work i looked at all 9 available signatures of that method, but couldn't find one that "allows you to filter by user".

2) re "finding out an item's path in a merge's target branch": 
let's say there are two branches $/myproj/product123-dev/ and $/myproj/product123-1.0 (1.0 was branched from dev), and two files:

i need to merge (the latest version of) them to

after calling (here ver represents the changeset in product123-dev that contains those 2 files):
GetStatus gs = wsp.Merge("$/myproj/product123-dev", "$/myproj/product123-1.0",
ver, ver, LockLevel.None, RecursionType.Full, MergeOptions.ForceMerge);
how do i check in the the pending merges (under "$/myproj/product123-1.0") as a result of this Merge() call
Note that i can't simply call wsp.GetPendingingChanges("$/myproj/product123-1.0"), because other developers(or even myself) might be working currently on a different file, say $/myproj/product123-1.0/area1/mainform.aspx, so i don't want to check in pending changes in those irrelevant files, only the pending merges as a result of that wsp.Merge() call, no more, no less.

Because wsp.Merge() doesn't return a PendingChange[], maybe the only possible way to achieve this is thru some kind of hack, such as replacing "$/myproj/product123-dev/" with $/myproj/product123-1.0/" for each source item to generate the target item and call wsp.GetPendingChange on each target item, as i described in the original question in this thread.

in spite of the possible conflicts, i still feel strongly that wsp.Merge() should include a PendingChange[] as part of the GetStatus returned when there are no conflicts.

QueryMergesWithDetails is only available in SP beta 1, but we are not allowed to use beta stuff in the production code, and besides, what i really need is to query "pending merges", not committed merges. I can't figure out how Merge with /preview is going to help with this i guess you meant calling Workspace.Merge(...,MergeOptions.NoMerge), is that ight exactly how can the target path be retrieved by calling this method


Richard Berg MSFT

PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top

Sorry, the API I was thinking of is VersionControlServer.QueryPendingSets(). That one allows you filter by username or workspace.

Also, Workspace.GetPendingChanges() is filtered by the workspace you're calling it from. Workspaces always belong to a single user, so there is no other filtering needed.

SP1 is no longer beta :)


PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top

I think you do not have a problem with quering pending changes - you have either GetPendingChanges on workspace you work with or QueryPendingChanges with workspace and user parameters set.

And as Richard said, your merges and check ins will be performed in context of your local workspace, so there will be no problem of changes belonging to others getting in the way.

As far as preview is concerned, when Merge is called with NoMerge option, it will not actually pend anything, but GetStatus result returned will be same as that of actual merge, so you can examine whether any merges will be performed or any conflicts occur.

Note that when you call Merge you may end up with conflicts that will require resolution prior to any check in performed (as you specify ForceMerge in call to Merge, you will probably end up with a handful of conflicts).

Regards, Eugene

Richard Berg MSFT

PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top

As I try to understand his program, I think workspace filtering may not be enough. He's describing a "merge service" that may be used by multiple people. Even if he filtered by username in QueryPendingChanges, it would only tell him that the service had pended all of the merges, not the user who requested them. This service definitely needs to use separate workspaces for each merge operation or chaos would ensue (especially since TFS v1 can't merge into pending changes).

The suggestions around NoMerge and QueryMergesWithDetails were to help him avoid trying to translate source paths into target paths without the server's help. Trust me, you don't want to go down this path. What if there's a rename on the server A parent rename A pending grandparent rename It's hard.

With NoMerge, you can get the target path from the events that are fired (a la tf.exe output). With QueryMergesWithDetails, you get the source->target relationship directly. In retrospect, both are too slow and too fragile (have to know ahead of time if either merge candidates exist or a merge history exists). The correct API call for this situation is GetBranchHistory().

My real opinion is that the whole service is unnecessary :) I really doubt you can make Merge->Resolve->Checkin any simpler than it already is in the clients we provide. If you do simplify it, you're certain to miss corner cases.


PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top

Thanks for the reply, Richard.

You are right, the app i'm working on needs to handle merge on behalf of developers. Here is the business scenario we have:

All source code for a single product is managed in two branches, say:
$/myproj/product123-dev/ and $/myproj/product123-1.0/ (well, maybe more in the future after versions like 1.1 or 2.0 are released)

The tool i need to create is a kind of Change Request Manager, because the organization has strict rules about code changes:
1. initially, the -dev and -1.0 branches have exactly the same code; changes can only be made to the -dev branch and then merged to -1.0 after passing a set of (mostly manual) tests.
2. developers can only change code (to the -dev branch) when there is a Change Request
3. each CR is managed as a record in a custom database table(t_chreq), with attributes such as the person/department that submitted it, date, priority, developer, tester, description, test instructions, estimated/actual effort, impact, target/actual completion date, cost, status etc. There is another table (t_chreqcs) that holds the changeset#s associated with a CR.
4. When a CR comes in, a developer is assigned to work on it.
5. the dev must check out/edit code in her local workspace, but cannot manually commit the code to TF, the reason being that each CR needs to track the changesets associated with it. Instead, after the dev has completed the work in the local workspace and thinks that the code change is ready to be committed, she needs to run our (yet-to-be developed) CR Manager tool, use this tool to commit (a subset of) pending workspace changes. The tool will record the changeset# (cs1) in t_chreqcs associating it with the CR's id).  The reason i said subset is that the dev might be working on another CR at the same time and checked out a couple other files for editing)
6. the CR Manager tool changes the CR's state to ready-for-test and sends an email to the tester assigned to the CR.
7. The tester gets the latest code of the product on to a test machine, builds it, and follow the test instructions to test it.
8. If the test failed, the tester uses CR Manager to change the CR's state to failed and notifies the dev to correct the error.
9. After fixing the bug, the dev will run CR Manager again to commit additional changes, resulting in another changeset# (cs2). Now both cs1 and cs2 are associated with the CR.
10. The tester is notified that the CR needs to be tested again, and this time around, everything looks good so the CR passes testing. The tester runs CR Manager to change the CR's state to tested, which triggers a merge of cs1 and cs2 to branch-1.0

--> Here  is where i need to write some code to do the merge. After the merge,CR Manager also records the resulting changeset# in t_chreqcs, associating it with the CR.

11. an email is sent to the build master to rebuild branch -1.0 and create a service-pack kind of installation package containing the changed assemblies as a result of the CR's code change.
With this tool, we can produce detailed reports on how many CRs have been implemented during a given period, and what source code files were affected etc. At the moment, i'm starting to wonder if this tool is really necessary, maybe we can utilize some existing features of TF to handle it


Richard Berg MSFT

PostPosted: Team Foundation Server - Version Control, Return value of Workspace.Merge() Top

For your system to work, I think you need to create a branch for each CR. That's more overhead than many people want, certainly, but it sounds like formal process isn't unwelcome in your business. If you don't do this,

  1. your testers won't be testing their CR; they'll also be testing random portions of other ongoing CRs
  2. automatic merging will get difficult very quickly. cherry-picking cs1, cs2, ... will generate a conflict at each step, even if the developer of this CR is the only person touching those files. this effect can be minimized if the developer confines their changes to a single subset of the source tree (untouched by others), but that's not always possible. given her own branch, the system will always be able to merge all her work at once, minimizing merge conflicts.

TFS has really good (and really extensible) work item tracking and reporting features. Consider using them as your backend rather than a custom database.