Why TFS Merge merges all files although they have not been changed - tfs

I have Dev and Release Branches in tfs.
I use release branch only for critical fixes after I release a version
Before each release I want to overwrite all changes made in Release branch with Dev branch. After that Release and Dev branches should be equal.
I'm using following commands to do so:
tf merge DEV RELEASE -r -force -version:1~T -noprompt
tf resolve RELEASE -r -auto:acceptTheirs
The problem is, that all files are in pending changes with "merge" change. I also see this in tfs history of file after check in.
Is this correct approach? Should I do things differently, e.g check in only changesets from last release? does it have any side effects?

You are using the -force parameter. That is the result of that c command.
"Ignores the merge history and merges the specified changes from the source into the destination, even if some or all these changes have been merged before"
https://msdn.microsoft.com/en-us/library/bd6dxhfy(v=vs.100).aspx
If you remove the -force option it will only merge the changes.

Related

How to reconcile TFS shelveset correctly after a successful gated check-in on the build agent?

Here is the simplified version of our gated check-in flow for a successful check-in:
Apply shelveset (build agent)
Build (build agent)
Revert Shelveset from Workspace (build agent)
Check in gated changes (CheckInGatedChanges activity on the controller)
Get the Changeset resulted from checking in the gated changes. (build agent)
This flow is very problematic. Indeed, suppose user A commits (submits to the gate) 100 source files affecting all the projects in the solution and then user B commits just 1 source file affecting just one project. How big would be the gated check-in build for the user B on the build agent?
The answer is that user B is going to "suffer" the same build as the user A.
The root cause: we undo the shelveset before checking in the gated changes and then get them again, this time in the form of a changeset. This bumps up the timestamps of the source files, making them newer then the binaries produced a moment ago from the same files.
That is a problem.
How do I solve it?
EDIT
Here what happens if I do not revert the shelveset, but get the respective changeset right away:
PS D:\tfs\DFGatedCheckInTest2> dir 1.txt
Directory: D:\tfs\DFGatedCheckInTest2
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 10/24/2014 10:36 AM 12 1.txt
PS D:\tfs\DFGatedCheckInTest2> tf get /version:C105656
D:\TFS\DFGatedCheckInTest2:
Conflict 1.txt - Unable to perform the get operation because you have a conflicting edit
Automatically resolved conflict: edit: D:\TFS\DFGatedCheckInTest2\1.txt as TakeTheirs
Undoing edit: 1.txt
PS D:\tfs\DFGatedCheckInTest2> dir 1.txt
Directory: D:\tfs\DFGatedCheckInTest2
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar-- 10/24/2014 11:42 AM 12 1.txt
PS D:\tfs\DFGatedCheckInTest2>
Notice the timestamp of the file. It was bumped up. We achieved nothing.
The reason why tf get /version:C12345 updates the time stamp is due to that being the default behavior for it in 2010. This was changed in 2012 and made configurable.
In Visual Studio 2012/TFS 2012 a feature was added that controls the file timestamp on get, read from Brian Harry's post from way back then:
Restore file modification time
When TFS gets files on to your local disk, it always sets the file modification time to the date/time that the get operation happened. There are some work practices where this is problematic. Some practices use the date stamp on the file for incremental deployment or other kinds of change management. SourceSafe had 3 options for setting the time stamp on files:
The time the file is gotten (this was the default and works very well in concert with make and other similar build dependency trackers).
The modification time that the file had when it was last edited before checkin.
The date/time that the file was checked in.
TFS 2010 and before only supported option #1. In TFS 11, we have added support for option #3. It can be set on a workspace by workspace basis. We plan to add support for #2 in the future but haven’t gotten there yet.
source
Back to the source of the issue
As you mention in your other question, you're using tf checkin /shelfset /force, which is where your problem lies. As the answer in your other question explains, that checkin goes directly against the server, the workspace on the server is unaffected and as such is left with the pending changes of unshelving that same shelfset.
tf checkin /force is also very dangerous in case anther developer had used by-pass gated build to check in changes. TFS will assume you know what you're doing and will overwrite these changes. So:
Developer 1 checks in filaA.txt
Build server starts gated checkin
Developer 2 checks in fileA.txt and bypasses gated checkin
Build server finishes and uses tf checkin /shelfset /force and thus overwrites the changes from developer 2
Instead, what the normal TFS workflow does, is check in the local changes on the workspace of the build agent. tf checkin $/ /recursive and it deletes the shelfset at the end of the build, in case of a succesful build and checkin.
This tells the build server to check-in the local changes in the workspace, and it will now know that it has the latest version, and won't have to update the time stamp. Next time the build is triggered the build agent will start with a get latest (to ensure that any bypass checkins are also fetched) and it will know these files are already up to date.
So in general your workflow, on the agent, should look like:
If workspace does not exist, create workspace and mappings
If there are any pending changes, undo them tf undo $/ /recursive
Perform tf get /recursive /version:T (get latest)
Unshelve your shelfset to the workspace of the agent
Build the code
Check in the local pending changes (tf checkin $/ /recursive), don't use /force
If all of that's succesful, delete the shelfset
If anything fails:
Undo all pending changes to reconcile the workspace
Leave the shelfset in tact
Fail the build.
That way the local workspace will better reflect what's going on and you won't have to perform a tf get /version:c12345 to mess up your dates.

How do I delete a folder in a branch of TFS, but not in the main part?

We need to delete a folder in one of our branches, but do not want it deleted in the main/root repository. The deleted folder is gone in ONE older version, but the newer versions retain it, as do the older versions.
I deleted it in the branch, merged to main, then in main did "undo pending changes" on that folder. The problem is each new merge to main, it wants to delete that folder again. How do I tell it to leave it in the main/root?
To prevent a changeset from being merged, you need to discard it. This is done from the Command Prompt.
The following example discards changeset 137 as a candidate for
merging into branch2.
tf merge /discard /version:C137 branch1 branch2 /recursive

last local or current changeset id

This question is related to the last change set id available in TFS, my query is, our tfs collection has multiple branches. I create a work space for each branch and build them.
Now my question is: I wanted to know the last local changeset id of the workspace with which I build the solution.
For example, I build MAIN branch 2 days back, now I wanted to know the last local change set id that is available locally. I used History command but some how it is giving the server changeset not the local changeset id.
Here are my arguments
tf history $/MAIN /collection:tfscollection /format:Detailed /sort:Descending /stopafter:1" ;
In this case, you want to look at the history of your workspace version. TFS tracks (server-side) the versions of files you have locally and defines your workspace version to be the version of the files that you have locally. Contrast that with the latest version which is the current version on the server.
You can use a version spec to indicate what version you want to query, T for the latest version and W for your workspace version.
Another problem, however, is that your current query will only look at the history for the folder you're specifying - that is, when it was added or branched. You will need to perform a recursive query to example all changesets that affect (are beneath) the specified folder.
Thus, your query to get the latest version on the server becomes:
tf history $/MAIN /collection:tfscollection /version:T /recursive /stopafter:1 /format:detailed /noprompt
And to get your workspace version:
tf history $/MAIN /collection:tfscollection /version:W /recursive /stopafter:1 /format:detailed /noprompt

Is there a command line TFS tool to track a changeset between branches?

Visual Studio 2010 has this nice GUI for allowing you to see the migration of a changeset between multiple branches. I would like to get this information in text format via the command line if possible. We run daily PowerShell scripts to check for unmerged changes between our Release branches and Trunk. This makes sure we don't forget to propagate a bug fix back to Trunk. However, what we are missing is the ability to then check if that same bug fix was propagated to a newer release branch e.g.:
Trunk ----------------------------------------------
\ \
\ ------- Release 2.0
-- Release 1.0
We can easily check for unmerged changes between Release 1.0 and Trunk but we also want to make sure those changesets get propaged down into Release 2.0 as well.
Running tf merge /candidate between Trunk and Release 2.0 wouldn't be effective because we would get a bunch of changesets related to new features implemented after the 2.0 release. Perhaps I could do a baseless merge candidate check (from Release 1.0 to Release 2.0)? Or perhaps TFS 2012 provides some new command line option for changeset tracking?
You'll probably want to use a combination of tf branches and tf merges. If these don't give you the information you need then I think you're going to be writing your own console application or powershell snapin using the TFS API

tfpt migrate for TFS doesn't do anything

I'm trying to use tfpt to migrate a shelveset from a source branch into a target branch, but it doesn't appear to do anything...not that I'd expect much more...but any chance anyone knows what's wrong? I'm following the instructions correctly I think...
I've got:
tfpt unshelve "DbMigrations" /migrate /source:$/TeamProject/Main /target:$/TeamProject/Releases/7.20
What happens after you run the command? You need to have a few things set up before migrating:
A workspace that encompasses both the source and target branches.
You need to run the command in a folder within the source.
Once you run the command you should be asked to merge the changes from the original shelfset into the destination branch and resolve any conflicts, which finally pends a changeset on your client. Nothing is touched on the server until you check that changeset into TFS itself.
I experienced the same problem and I could not get it to work by specifying the shelveset name. However, I discovered that if you remove the name of the shelveset altogether, TFS will pop up a window with a selection list of available shelvesets to choose from. Select the desired shelveset and perform all other merge operations as per normal.
Example: c:[mapped workspace target path] > tfpt unshelve /migrate /source:"$/Sourcepath" /target:"$/targetpath"
You need to use the branch paths on the TFS server, not your local machine. To find the paths, go to source control explorer in visual studio, right click the branch, advanced > properties, and you want the branch name, not the local path. If the path has spaces, wrap it in double quotes.

Resources