Git-TF: Getting Started Guide

Git-TF V2.0.3

About the tools

Git-TF is a set of command line tools that facilitate the use of a local Git repository with TFS. These tools make it easy to clone sources from TFS, fetch updates from TFS, and to update TFS with changes committed locally in Git.

Release notes

See the Git-TF Release Notes for details on new features and bug fixes.

Installation

Supported Platforms

Git-TF is supported on the following platforms:

Supported Versions of TFS

Git-TF is supported for use with the following versions of TFS:

Prerequisites

Any of the following versions of the Java runtime (latest versions available from http://www.java.com):

It is recommended that the latest version of Git is installed as well. It is not strictly needed to use Git-TF, but it will be useful in working with the local repository created by the tools. Information about the latest Git downloads can be found on: http://git-scm.com/downloads

Installing Git-TF

  1. Extract the contents of Git-TF-Release-Preview.zip to a folder on your local machine, i.e. C:\git-tf on Windows, or /user/git-tf on Mac/Linux.
  2. Add the path where you extracted Git-TF (i.e. C:\git-tf) to your PATH environment variable.
  3. Add the path where java.exe is installed (i.e. C:\Program Files (x86)\Java\jre7\bin) to your PATH environment variable.

Example Usage

Individual Developer with a New Repo

A typical workflow for an individual developer using the Git-TF tools are as follows.

  1. git tf clone http://myserver:8080/tfs $/TeamProjectA/Main
    Changes are cloned down from TFS to git
  2. Make changes to the file in the Git repo
  3. git commit -a -m "commit one"
    (commit changes locally)
  4. Make more changes
  5. git commit -a -m "commit two"
  6. git tf pull --rebase
    Fetch the latest changes from TFS and rebase master on top of the fetched changes
  7. git tf checkin
    Check in the changes from "commit one" and "commit two" as a single TFS changeset

Development Team with an Existing Repo

For a team working with an existing Git repo, a developer sharing changes to TFS using Git-TF would use the following workflow.

  1. git tf configure http://myserver:8080/tfs $/TeamProjectA/Main
    Configure the existing repo's relationship with TFS
  2. git tf pull
    Fetch the latest changes from TFS and merge those changes with the local changes. Note, merging is important when working in a team configuration. See "Rebase vs. Merge" below.
  3. git commit -a -m "merge commit"
  4. git tf checkin
    Check in the merge commit as a single TFS changeset
  5. git push
    Push the merge commit to the origin

Commands

Below is the list of commands that are currently supported by Git-TF. These commands can be run from a command window by typing "git tf <command name>".

Help

git tf help

Displays the list of available Git-TF commands.

git tf help <command>

Displays the detailed syntax for a given command, including all optional flags.

Clone

git tf clone http://myserver:8080/tfs/collectionName $/TeamProjectA/Main [--deep]

Initializes a new git repo from an existing path in a TFS server. When cloning from TFS, by default a shallow clone is performed, i.e. only the latest changeset is downloaded and used to create the first Git commit. The optional --deep flag may be used to clone each TFS changeset for the specified path into the new Git repo. Note, when using the --deep option, all future git tf fetch, git tf pull, and git tf checkin operations will default to --deep.

Configure

git tf configure http://myserver:8080/tfs/collectionName $/TeamProjectA/Main [--deep]

Configures an existing git repo to be able to communicate with a TFS server. Like the clone command, the --deep option may be used to set the default for future fetch and checkin operations.

Checkin

git tf checkin [--deep]

Checks in the changes made in the Git repo into TFS. By default, the checkin command will create a single TFS changeset for the aggregate of all changes made on the current branch in Git since the last checkin to TFS. When used with the --deep option, a TFS changeset will be created for each Git commit on the current branch since the last checkin to TFS.

Fetch

git tf fetch [--deep]

Fetches changes made in TFS as a new commit in Git, and references the new commit as FETCH_HEAD. By default, a single commit will be created in the Git repo with the aggregate changes since the last fetch. When used with the --deep option, a Git commit will be created for each TFS changeset that was created since the last fetch.

Pull

git tf pull [--deep] [--rebase]

Fetches changes made in TFS as a new commit in Git, and merges the commit with the latest commit in the current branch. By default, the fetch performed by the pull command is shallow, but the --deep option may be used to create a Git commit for each TFS changeset created since the last fetch. Also, merge is used by default when pulling, but the --rebase option may be used to perform a rebase instead.

Shelve

git tf shelve myshelveset

Shelve the changes made in the Git repo into TFS. Shelve operates similarly to the git tf checkin --shallow option in that all aggregate changes since the last checkin will be created as a single shelveset.

Unshelve

git tf unshelve shelvesetName [--user|-u=shelvesetOwner]

Unshelve the changes from the TFS shelveset into a stash in the git repository. To apply the shelveset content in the repository execute git stash apply. When the stash is applied in the repository, the changes downloaded by the unshelve command will be merged with the current HEAD.

Shelvesets

git tf shelvesets [shelvesetName] [--user|-u=shelvesetOwner] [--details] [--delete]

Lists the shelvesets available on the server that match the name and owner specified. If the --details flag is specified, more shelveset details will be listed. This command can also be used to delete shelvesets from the server.

Working with Teams

The Git-TF tool is most easily used by a single developer or multiple developers working independently with their own isolated Git repos. That is, each developer uses Git-TF to clone a local repo where they can then use Git to manage their local development that will eventually be checked in to TFS. In this "hub and spoke" configuration, all code is shared through TFS at the "hub" and each developer using Git becomes a "spoke". Developers looking to collaborate using Git's distributed sharing capabilities will want to work in a specific configuration described below.

Most often, developers collaborating with Git have cloned from a common repo. When it comes time to share divergent changes, conflict resolution is easy because each repository shares the same common base version. Many times, conflicts are automatically resolved. One of the keys to this merging of histories is that each commit is assigned a unique identifier that is generated by the contents of the commit. When working with Git-TF, two repositories cloned from the same TFS path will not have the same commit IDs unless the clones were done at the same point in TFS history, and with the same depth. In the event that two Git repos that were independently cloned using Git-TF share changes directly, the result will be a baseless merge of the repositories and a large number of conflicts. For this reason, it is not recommended that teams using Git-TF ever share changes directly through Git (i.e. using git push and git pull).

Instead, it is recommended that a team working with Git-TF and collaborating with Git do so by designating a single repo as the point of contact with TFS. This configuration may look as follows for a team of three developers:

          [TFS]      [Shared Git repo]
            |         ^ (2)  |       \
            |        /       |        \
            |       /        |         \
            V (1)  /         V (3)      V (4)
       [Alice's Repo]   [Bob's Repo]   [Charlie's Repo]
    

In the configuration above the actions would be as follows:

  1. Using the git tf clone command, Alice clones a path from TFS into a local Git repo.
  2. Next, Alice uses git push to push the commit created in her local Git repo into the team's shared Git repo.
  3. Bob can then use git clone to clone down the changes that Alice pushed.
  4. Charlie can also use git clone to clone down the changes that Alice pushed.

Both Bob and Charlie only ever interact with the team's shared Git repo using git push and git pull. They can also interact directly with one another's repos (or with Alice's) , but should never use Git-TF commands to interact with TFS.

When working with the team, Alice will typically develop locally and use git push and git pull to share changes with the team. When the team decides they have changes to share with TFS, Alice will use a git tf checkin to share those changes (typically a git tf checkin --shallow will be used). Likewise, if there are changes that the team needs from TFS, Alice will perform a git tf pull, using the --merge or --rebase options as appropriate, and then use git push to share the changes with the team.

Rebase vs. Merge

Once changes have been fetched from TFS using git tf pull (or git tf fetch), those changes must either be merged with the HEAD or have any changes since the last fetch rebased on top of FETCH_HEAD. Git-TF allows developers to work in either manner, though if the repo that is sharing changes with TFS has shared any commits with other Git users, then this rebase may result in significant conflicts (see The Perils of Rebasing). For this reason, it is recommended that any team working in the aforementioned team configuration use git tf pull with the default --merge option (or use git merge FETCH_HEAD to incorporate changes made in TFS after fetching manually).

Recommended Git Settings

When using the Git-TF tools, there are a few recommended settings that should make it easier to work with other developers that are using TFS.

Line Endings

core.autocrlf = false

Git has a feature to allow line endings to be normalized for a repository, and it provides options for how those line endings should be set when files are checked out. TFS does not have any feature to normalize line endings - it stores exactly what is checked in by the user. When using Git-TF, choosing to normalize line endings to Unix-style line endings (LF) will likely result in TFS users (especially those using VS) changing the line endings back to Windows-style line endings (CRLF). As a result, it is recommended to set the core.autocrlf option to false, which will keep line endings unchanged in the Git repo.

Ignore case

core.ignorecase = true

TFS does not allow multiple files that differ only in case to exist in the same folder at the same time. Git users working on non-Windows machines could commit files to their repo that differ only in case, and attempting to check in those changes to TFS will result in an error. To avoid these types of errors, the core.ignorecase option should be set to true.