Access TFS From Linux!
The Microsoft Team Foundation Cross-Platform Command-Line Client allows developers to access Team Foundation Server for version control.
Preparation
Before installation, take some time to consider how you will setup your workspace path. My previous post, Mounting A Directory In Linux will help provide a couple of things to consider, such as mitigating paths that may become too long for TFS checkins.
Download The Client
Download the Anywhere Client and unzip.
Setup The Environment Variables
For
sh
edit
~/.profile
For
bash
edit
~/.bashrc
Add an alias so you don’t have to type the full path to the executable
alias tf='/home/user/path/to/anywhere-client/TEE-CLS-x.x.x/tf'
You can also consider setting the following environment variables to make things a bit smoother.
Save yourself from having to re-type your credentials each time you execute a command
export TF_AUTO_SAVE_CREDENTIALS='1'
Setup your diff and merge tool of choice. In this example I’m using Beyond Compare.
export TF_DIFF_COMMAND='/usr/bin/bcompare %1 %2' export TF_MERGE_COMMAND='/usr/bin/bcompare %1 %2 %4'
Setup The Workspace
Before setting up a workspace, if you’re unsure if one already exists for the machine, you can check with
tf workspaces
This also prints the Collection after you’ve setup a workspace if you want a quick reminder of which one is being used.
To create a new workspace, have the Collection url and your credentials available and use
tf workspace -new my-workspace-name -collection:http://tfsserver:8080/tfs/Collection
Map A Project
Project directories are mapped with the workfold command
tf workfold -map -collection:'http://collection:8080/tfs/collectionname' -workspace:workspace-name $/TFS/Project/Path /local/project/path/target
Pulling Code
To pull a project
tf get .
or
tf get -recursive some/nested/folder/path/
Ignore File
Much like the .gitignore and .hgignore files, you can create the .tfignore for TFS to ignore directories and files. For example
touch .tfignore vim .tfignore
Sample file contents
*\bin\* *\obj\* *\dist\* *.txt *\packages\*
Checkout
Checking out a file can be as granular as a specific file or as broad in scope as multiple directories. Note that simply editing a code file will mark it as changed. To checkout the current location and subdirectories
tf checkout -recursive .
Getting The Status of TFS Changes
To view the status of detected TFS changes between the TFS server and the local machine
tf status .
diffing files
Using the appplication set in the Environment Variable
TF_DIFF_COMMAND
mentioned above, you can view the diff between the server version and your local version with
tf difference filename
Checkin
Here’s an example of creating, adding and checking in a file for version control.
touch newfilename tf add newfilename tf checkin -comment:'Adding a new file named newfilename'
More Help
There are many more options beyond these, “Getting Started” basics. Here is the output of
tf -h
at the time of this writing for reference.
Team Explorer Everywhere Command Line Client (version 14.114.0.201703081734)
Available commands and their options:
add [-lock:none|checkin|checkout] [-type:<value>] [-recursive] [-silent] [-noignore]
<localItemSpec>...
branch [-version:<value>] [-noget] [-lock:none|checkin|checkout] [-recursive] [-checkin]
[-comment:<value>|@valuefile] [-author:<value>]
[-notes:'note'='value'[;'note2'='value2'[;...]]|@notefile] <oldItemSpec> <newLocalItem>
branches [-version:<value>] <itemSpec>...
changeset [-latest] [-comment:<value>|@valuefile]
[-notes:'note'='value'[;'note2'='value2'[;...]]|@notefile] [changenumber]
checkin [-all] [-author:<value>] [-comment:<value>|@valuefile]
[-notes:'note'='value'[;'note2'='value2'[;...]]|@notefile] [-override:<value>|@valuefile]
[-recursive] [-validate] [-bypass] [-force] [-noautoresolve]
[-associate:<workItemID>[,<workItemID>...]] [-resolve:<workItemID>[,<workItemID>...]]
[-saved] [<itemSpec>...]
checkout [-recursive] [-lock:none|checkin|checkout] [-type:<value>] <itemSpec>...
delete [-lock:none|checkin|checkout] [-recursive] <itemSpec>...
delete -detect [-lock:none|checkin|checkout] [-recursive]
destroy [-keephistory] [-startcleanup] [-preview] [-silent] [-stopat:<value>] [-noprompt]
itemspec1[;versionspec][;XdeletionID] [itemspec2...itemspecN]
difference [-recursive] <itemSpec> <itemSpec2>
difference [-shelveset:<value>] [-recursive] <shelvesetItemSpec>
difference [-version:<value>] [-recursive] <itemSpec>
dir [-version:<value>] [-recursive] [-folders] [-deleted] <itemSpec>...
eula [-accept]
get [-version:<value>] [-recursive] [-preview] [-force] [-all] [-overwrite] [-noautoresolve]
[<itemSpec>...]
getcs -changeset:changeset [-latest]
help [-listexitcodes] [<command>]
history [-version:<value>] [-stopafter:<value>] [-recursive] [-user:<value>]
[-format:brief|detailed|xml] [-slotmode] [-itemmode] <itemSpec>
info [-recursive] [-version:<value>] <itemSpec>...
label [-owner:<value>] [-version:<value>] [-comment:<value>|@valuefile]
[-child:fail|replace|merge] [-recursive] <labelName>[@<scope>] <itemSpec>...
label -delete [-owner:<value>] [-version:<value>] <labelName>[@<scope>]
labels [-owner:<value>] [-format:brief|detailed|xml] [<labelNameFilter>]
lock [-recursive] [-lock:none|checkin|checkout] <itemSpec>...
merge [-recursive] [-force] [-candidate] [-discard] [-version:<value>]
[-lock:none|checkin|checkout] [-preview] [-baseless] [-nosummary] [-noimplicitbaseless]
[-format:brief|detailed|xml] [-noautoresolve] <source> <destination>
merges [-recursive] [-format:brief|detailed|xml] [<sourceItem>] <destinationItem>
online [-adds] [-deletes] [-diff] [-exclude:<value>[,<value>]] [-recursive] [-preview]
[<itemSpec>...]
print [-version:<value>] <itemSpec>
property [-output:<value>] [-recursive] [-version:<value>] <itemSpec> [<propertyname>]
property -deleteall [-recursive] <itemSpec>
property -deletevalues:<value>[,<value>] [-recursive] <itemSpec>
property -setvalues:@valuefile|name1=value1[;name2=value2;name3=@valuefile;...] [-recursive]
<itemSpec>
reconcile [-teamProject:<value>]
reconcile -buildName:<value> [-teamProject:<value>] [-recursive] [<itemSpec>...]
reconcile -changeset:changeset [-recursive] [<itemSpec>...]
reconcile -forgetBuild:<buildName> [-teamProject:<value>]
rename [-lock:none|checkin|checkout] <oldItem> <newItem>
resolve [-auto:AutoMerge|TakeTheirs|KeepYours|OverwriteLocal|DeleteConflict|KeepYoursRenameTheirs|
External] [-preview] [-converttotype:<value>] [-recursive] [-newname:<value>] <itemSpec>
resolve [-auto:AutoMerge|TakeTheirs|KeepYours|OverwriteLocal|DeleteConflict|KeepYoursRenameTheirs|
External] [-preview] [-overridetype:<value>] [-recursive] [-newname:<value>] <itemSpec>
resolvePath [-collection:<url>] [-workspace:<value>] <serverPath>
resolvePath <serverPath>
rollback -changeset:changesetfrom~changesetto [-recursive] [-lock:none|checkin|checkout]
[-version:<value>] [-keepmergehistory] [-noautoresolve] [<itemSpec>...]
rollback -toversion:versionspec [-recursive] [-lock:none|checkin|checkout] [-version:<value>]
[-keepmergehistory] [-noautoresolve] <itemSpec>...
shelve [-move] [-replace] [-comment:<value>|@valuefile] [-recursive] [-validate] [-saved]
<shelvesetName[;owner]> <fileSpec>...
shelve [-replace] [-comment:<value>|@valuefile] [-validate] [-saved] <shelvesetName[;owner]>
shelve -delete [-collection:<url>] [-validate] [-saved] <shelvesetName[;owner]>
shelvesets [-owner:<value>] [-format:brief|detailed|xml] [<shelvesetName>]
status [-workspace:<value>] [-shelveset:<value>] [-format:brief|detailed|xml] [-recursive]
[-user:<value>] [-nodetect] [<itemSpec>...]
undelete [-noget] [-lock:none|checkin|checkout] [-newname:<value>] <itemSpec>[;deletionID]...
undelete [-noget] [-lock:none|checkin|checkout] [-recursive] <itemSpec>[;deletionID]...
undo [-recursive] <itemSpec>...
unlabel [-recursive] <labelName>[@<scope>] <itemSpec>...
unshelve [-move] [-recursive] [-nomerge] [-noautoresolve] [-format:brief|detailed|xml]
<shelvesetName[;owner]> [<itemSpec>...]
uu [-recursive] [-noprompt] <itemSpec>...
workfold [-collection:<url>] [-workspace:<value>] <serverFolder>
workfold [-map] [-collection:<url>] [-workspace:<value>] <serverFolder> <localFolder>
workfold [-workspace:<value>]
workfold <localFolder>
workfold -cloak [-collection:<url>] [-workspace:<value>] <serverFolder>|<localFolder>
workfold -decloak [-collection:<url>] [-workspace:<value>] <serverFolder>|<localFolder>
workfold -unmap [-collection:<url>] [-workspace:<value>] <serverFolder>|<localFolder>
workspace [-collection:<url>] [-comment:<value>|@valuefile] [-newname:<value>]
[-filetime:current|checkin] [-permission:Private|PublicLimited|Public]
[<workspacename;[workspaceowner]>]
workspace -delete [-collection:<url>] [<workspacename;[workspaceowner]>]
workspace -new [-noprompt] [-template:<value>] [-computer:<value>] [-comment:<value>|@valuefile]
[-collection:<url>] [-location:server|local] [-filetime:current|checkin]
[-permission:Private|PublicLimited|Public] [<workspacename;[workspaceowner]>]
workspaces [-owner:<value>] [-computer:<value>] [-collection:<url>] [-format:brief|detailed|xml]
[-updateUserName:<user@domain>|<domain\user>] [-updateComputerName:<value>] workspaceName
workspaces -remove:<workspace1>[,<workspace2>,...] -collection:<url>
Options accepted by most commands:
[-login:domain\username,password] | [-login:username@domain,password]
-collection:<url>
-continueOnError
-exitcode
-help
-noprompt
-nosummary
-outputSeparator:<value>
-proxy:<url>
-server:<url>
-workspace:<value>
Options may be started with any of: -
For general help, view the 'help/index.htm' file installed with the program.
For help on a specific command, supply the command name as an argument
to the help command. For example: 'tf help checkin'