views:

384

answers:

3

I have two TFS branches that do not have a direct parent/child relationship in TFS. In a certain revision, 94 in my example, several items were deleted. I have been tasked with applying those deletes to the main branch. I'd like to do so through a baseless merge. I tried the following command to do so:

tf merge /baseless /recursive /version:94 .\programs\program1 ..\Release\programs\program1

Most of the items in the tree were marked as "merge", and some were marked as "merge edit". However, none of the items were deleted at the destination. On a whim i tried to merge over a single delete like so:

tf merge /baseless /recursive /version:94 .\programs\program1\source1.cs ..\Release\programs\program1\source1.cs

I got the following error message:

The item [TFS_PATH] does not exist at the specified version.

How do I do this? Is there a way to avoid making all those deletes myself?

+1  A: 

The Patterns & Practices documentation implies that you have to resolve the merge conflicts yourself, once. (Caveat: I haven't tried this.)

EDIT: P.S. See also The morning after a TFS Baseless Merge.

TrueWill
+1  A: 

Nope, sorry, can't be done. Baseless merge is very dumb, amounting to little more than "take the contents of a folder and copy it somewhere else." As the name Baseless implies, there is no historical information with which to do a diff. In practice that means file contents propagates but not namespace changes (deletes, undeletes, renames). You can kinda-sorta diff file contents by matching up similar filenames and crossing your fingers, but diffing the namespace really does require knowing what the tree structure looked like last time the branches were synchronized, so TFS doesn't even bother.

That said, if you know the changeset # where the desired deletes were made, scripting out the deletes yourself is no biggie.

$tfs = Get-TfsServer -path . -all
$deletes = get-tfschangeset 94 | % { $_.changes } | ? { ($_.changetype -band $tfs.VCS_ChangeType::delete) -ne 0 } | % { $_.serveritem }
($deletes -replace "$/branch1" "$/branch2") | Add-TfsPendingChange -delete

[untested but should work]

Richard Berg
You forgot a comma in the replace command (or clause or whatever its called). I'm still working on debugging it.
Justin Dearing
Thanks, feel free to edit my post when you've got it working.
Richard Berg
Richard, I don't have the reputation for that. I'm working on it though.
Justin Dearing
+1  A: 

I experimented a bit and here is my version of the above. seems to work for me:

get-tfsChangeset xx |% {$.changes} |? {($.changetype -band $tfs.VCS_ChangeType::delete) -ne 0 } |% {$_.item.serverItem -replace "\$/branch1","$/branch2"} | Add-TfsPendingChange -delete

to make it even more useful, one can parametrize the changeset number and branch paths to allow for more convenient processing.

for example, to process all deletes in a given branch run this from the source location:

$sourcePath="\$/MySourcePath" $destPath="$/MydestPath"

Get-TfsItemHistory ./*.sql -r -IncludeItems | %{$.changes} | ? {($.changetype -band $tfs.VCS_ChangeType::delete) -ne 0 } | % {$_.item.serverItem -replace $sourcePath,$destPath} | Add-TfsPendingChange -delete

Mordechai