I've been having a look at the capabilities of changesets and merges, in particular I was interested in the following:
* Cherry-pick merges -- you can merge specific file change to another branch without merging the changes that were included in previous versions of those files. Thus, if you've got 2 bug fixes which touch the same file, you can merge the second one without merging the first.
So, I conducted the following simple experiment, involving a single file, and merge from a parent branch $/Test/Main to a child $/Test/Main-branch.
I added a file A.txt into $/Test/Main, with a single line of text, Original Code.
History
Changeset Change User ...... etc
1052 add me
I then edited A.txt on $/Test/Main adding, another line of text below the first, First Change.
History
Changeset Change User ...... etc
1053 edit me
1052 add me
Again, I edited A.txt on $/Test/Main adding, another line of text below the first, Second Change.
History
Changeset Change User ...... etc
1054 edit me
1053 edit me
1052 add me
So now A.txt on $/Test/Main contains the following lines:
Original Code
First Change
Second Change
I then merged (using selected changeset) changeset 1052 into the branch, $/Test/Main-branch
History of A.txt on the branch
Changeset Change User ...... etc
1055 merge, branch me
So now on the branch, $/Test/Main-branch, A.txt has a single line:
Original Code
Ok, so far so good.
Now, what if I decide that I want to 'cherry pick' changeset 1054 (excliding 1053), into the branch
Ok, I then merge (using selected changeset), changeset 1054 into the branch, $/Test/Main-branch.
This is where merge does not seem to work, as I would expect.
My understanding of changesets was along the lines of the following. Where each change is atomic, rather than an incrementing version.
C1052: [Original Code]
C1053: [First Change]
C1054: [Second Change]
So I expected merging C1054 from $/Test/Main into the $/Test/Main-branch branch into which I previously merged C1052 would produce the following:
C1052: [Original Code]
C1054: [Second Change]
(i.e. leave out C1053, which I did not select)
Instead, a resolve conflicts dialog popped up. I used the Resolve... rather than auto, to see what's going on.
I see that there is no option to merge only C1054:[Second Change], rather an option to merge C1054:[First Change][Second Change].
So the C1053 change seems to be bundled in with C1054. This is almost as if C1053 is a version, and not an atomic cherry!
I did a few other experiments along the same lines, for example a simple vb project, but always got the same result.
----------------------- --------------------------
Could anyone explain What is the expected functionality in the area of changesets and merge at the single file level
----------------------- --------------------------

Changesets, Merges, and atomic cherries.
Siva.M
If I'm reading your scenario correctly, the behavior you're seeing is because the source of the merge is not mapped. It's "by design" but admittedly hard for the user to see why, which is why we recommend you have a complete, sunc workspace to perform merges from. That is, best practices for getting merge to do what you expect:
We should have more guidance around this in the RTM docs.
Greg Billinge
$/TeamProjectFolder/branches
/trunk
In trunk I have the main project code and in branches all branches I create. Trunk looks like
trunk/solutiondir
/soultiondir/libraryproj
/solutiondir/librarytestproj
and branches like this
branches/client/solutiondir
/client/soultiondir/libraryproj
/client/solutiondir/librarytestproj
I then have two workspaces, "trunk" and "client"; "trunk" maps all the files/directories under $TeamProjectFolder/trunk and "client" maps $TeamProjectFolder/branches/client. Initially both trunk and branches/client are identical. There are no pending changes.
I then go through this process, all the editing is done in the workspace for the portion of the tree I'm working with, and this is all done in VS2005.
In trunk I edit a file and add the lines. I change to the client workspace and merge those changes into the branch, so both trunk and client have all three added lines and both are checked-in.
In the client I add "//line 1.5" and checkin the changes
In the client I change "line 3" and check in the changes
I switch back to the trunk workspace and merge from the branch into the trunk (i.e. in the source control explorer I right click on the file I want to merge into the trunk and select merge). I select the first change set. I get no dialog and the merge happens automatically. If I look at the file in trunk all the changes are there.
I can do this consistently. I've now tried in on several files in the repository and it doesn't matter what I cherry-pick, if it's the first or last changeset,
Stepe
I've marked Richard's reply as the 'Answer'.
However, does anyone have info on whether an enhanced merge tool would be able to provide a finer grained merge ... catering for change on a single line Does such a merge tool already exist
unlikely
Merging with the source unmapped is definitely supported. All of the merges you described should work fine. The only potential "gotcha" is that, from the command line, users should probably use a Tip versionspec because the default (Workspace) may not be what they expect.
(I still can't reproduce any situation where merging 1 of several candidate changesets fails to generate a conflict.)
Merging with any part of the target tree unmapped or remapped can be problematic. We support it, but it makes the computation of source items into target space very tricky, because any item in the source could also have been renamed (within the source tree, into it, out of it, between tree depths, cyclically, dependently...), and any rename can in turn affect the mapping between local & server space.
That's kind of hand-wavy. Let's think through an example. Remapping on its own isn't so bad: the merge result will be indecipherable (and probably unusable) in some rename edge cases, but at least it will be "correct" by TFS semantics.
If your mappings fail to include an item in the target tree due to overlaps or cloaks, then the real fun begins. Merges on that slot won't be pended the way you want. E.g. a rename or undelete whose target is that slot will merge across as a merge + branch instead of merge + rename/undelete. That doesn't sound catastrophic -- you "only" confuse the target item's version history, not its content -- until you try your next merge from tgt back to src. Now there are two items with the same name in the reverse merge's target space (src/*). Both items might have pending changes that need to merge, but only one can possibly happen; the other will error out. You're stuck, until someone that doesn't have any cloaks underneath tgt performs the merge for you.
Their recovery procedure isn't cake either. Merge source to target again. Ensure all changes reported to be in the just-branched filename actually reside in the correct file. Delete the just-branched file and checkin. But the saga doesn't end there...you then have to run tf merge <justBranchedFile> <srcFile> /discard and checkin. Otherwise the next reverse merge (tgt to src) would delete the file.
In sum: for everyone's sanity, don't go down that path. Just say no.
TNROROC
ddmeightball
As far as getting cherry-pick merges to do exactly what you want, it's intractable. Going back to your example where 3 lines were added on successive checkins, maybe it looks like this...
...in which case, line 2 definitely needs to be merged along with line 3. Or maybe it looks like this...
....in which case we might want line 3 to be ported but not line 2, since the stable branch is well beyond the point where there's time to work on TODOs.
As you pointed out, other file types like XML can make intra-line dependencies a lot more complicated. Merge engines are just text parsers and don't even try to guess at semantics; if there's any doubt, we want it to generate a conflict* so that a human will look at it and do the right thing.
*The term "conflict" is overloaded here, resulting from the two meanings of "merge." The source control operation invoked by 'tf merge' compares two branches in the tree, and throws conflicts (meaning #1) when it encounters things like Version Conflicts and Namespace Collisions and Writable Files. Then when it's time to combine the contents of different file versions, that's also called a "merge," which can result in "conflicts" (meaning #2) when diffs between Source<->Base and Target<->Base occur within the same textual block. A cherry-pick Merge1 where the file has been edited in a changeset prior to the one(s) being merged always results in a Conflict1. You can try to resolve it automatically via a Merge2, but if that encounters a Conflict2, then TFS will not let you resolve it unless you explicitly overwrite the file or use a manual merge tool.
Thus: my spaced-out example can be auto-merged since there is no question what is intended. With your initial example, there's no way to tell for sure. If you blindly AcceptTheirs, TFS will bring over both new lines while a different product might have only brought Line 3, but what we really want is for you to look at it. Once you fire up the manual merge (either the one we provide, or a 3rd-party tool of your choice), it should be straightforward to complete the merge with whatever granularity you like, down to a single character if appropriate.
JimmyFo
TFS merge, like most textual merge engines, works in blocks. It looks like all of the changes you're making are computed as belonging to the same block. Thus, when TFS computes the 3-way merge of that block, it looks something like this:
Base [source;C1053]:
Line 1
Line 2
Yours [target]:
Line 1
Theirs [source;C1054]:
Line 1
Line 2
Line 3
You can see exactly what's happening by using a manual merge tool. (Since this block has "changes" between Yours<->Base and Theirs<->Base, it shouldn't have let you resolve without doing a manual merge or an overwrite.)
Let's demonstrate a more realistic cherry-pick. Create file.txt like this:
Add & Checkin. Branch to file-branch.txt. Now check it out and change it to this:
Checkin. Edit it once more to this:
Checkin. Now, if you do a cherry-pick merge of the 2nd changeset, only the last line will be affected. Make sense
graydippy
Richard
------------------------- -------------------------
Thanks. Your scenario does work. But I think my scenario is still valid.
It seems that a changeset is attached to the last line of the previous changeset. So since I had only one line in the original, only the first change could attach to it. The second change, had to attach to the first change, not the original.
C1: Original
C2: First Change (attached to the line C1: Original)
C3: Second Change (attached to the line C2: First Change)
Above, C2 is linked to C1, C3 is linked to C2.
This leads to the merge feature that I saw, where if the line that a change follows, is not selected for merge (or has not been previously merged), the merge (has to...hmmm) take that line with it...because that is what it is linked 'through' to the original. I do wonder though, if this is a merge tool feature, rather than a changeset feature.
In your scenario there are enough attachment points (if I can call them that).
If, I change my scenario to be (like yours), it works:
C1: Original line 1
C2: First Change (attached to the line C1: Original line 1)
C1: Original line 2
C3: Second Change (attached to the line C1: Original line 2)
However, I still think my scenario is a valid point to make. Changes to a single file are not guaranteed to have 'original' lines to be attached to. I've noticed that in particular, changes to GUI code where labels, buttons, or fields may be added or changed by separate pieces of work, are often on adjacent lines. What about XML files Seperate changesets will end up at merge time in contiguous code blocks, even if this is not wanted. Often, these changes are on the same single line!
I would even have liked to see the cherry picking of changeset capability, right down to individual character level! This would cover the situation mentioned above, where changes occurring on a single line need separate merging.
------------------------- -------------------------
Is the fine grained cherry picking capability, missing at the fundamental changeset level, or is it only missing at the merge/resolve tool level, and therefore something that an enhanced merge tool could handle by better interpreting the changesets
< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
Maxim Michtchenko
Andrej Benedik
I'm using VS TeamSuite trial edition and Beta3 refresh of VSTS.
I have a c# file that exists in the main tree. I've created a branch that contains that file and several others. The file already existed in the branch before I started the test. In the branch I added I added several lines
// line 1
// line 2
// line 3
commited this change and merged it back into the main tree so that all these lines appear in both the main file and the branched file.
In the branched file I add another comment so I now have
// line 1
// line 1.5
etc.
and I commit
then I change line 3 so I have
// line 1
// line 1.5
// line 2
// line 3 v2
and I commit.
In Visual Studio I right click on the file, select merge and as my merge target select the file in the main tree. I pick the 2nd changeset, the merge happens automatically (no resolve dialog) and the main file ends up looking exactly the same as the branched file (i.e. all four lines are in there).
I have tried this test following your steps exactly and it works as you describe, however I'd expect my scenario to work the same way.
One other thing that may be different is that I'm using different workspaces for the main trunk and the branch.
Am I missing something
onkeldoktor
I can't reproduce what you describe -- adding my 3-line example to the end of a file generates a conflict, and resolving as AcceptMerge brings over just the selected change.
Which workspace did try to pend the merge in Make sure both trees in it are up to date. Even if the Merge (meaning #2) engine ends up calculating the base version different from what you'd expect for whatever reason, a cherry-pick Merge (meaning #1) should always generate a version conflict.