Git-Tfs - Exclude certain branches from migration

The time to migrate from your TFVC repository to GIT has come. Great! The process is quite straightforward. You can get all your source control history recreated in GIT using Git-Tfs. The tool can even include the changesets from the branches that has already been merged. But, what if the process fails on the specific merge changeset or you want to skip some of the branches?

Prerequisites

Get the Git-Tfs tool and make sure that it is in your PATH.

Process

Let’s assume that we need to migrate from a TFS repository to GIT. The repository contains the Main branch with the following history.

Changeset    Description
----------------------------------
39	         Merge Branch6 to Main
34	         Merge Branch5 to Main
29	         Merge Branch4 to Main
24	         Merge Branch3 to Main
20	         Merge Branch2 to Main
10	         Merge Branch1 to Main
5	         Create Main folder

As you can see there are several branches that have been merged to Main. The resulting GIT repository needs to contain all the intermediate changesets from these branches. There should be a merge commit for every branch that was integrated.

Migrate from TFS to GIT with branches history

To perform the migration we need to invoke Git-Tfs clone command. It initializes a new Git repository from a TFS repository. The command allows to pass the branches parameter, which specifies the strategy to manage branches.

 --branches=VALUE    Strategy to manage branches:
                        * none: Ignore branches and merge changesets,
                        fetching only the clone tfs path
                        * auto:(default) Manage merged changesets and
                        initialize the merged branches
                        * all: Manage merged changesets and initialize
                        all the branches during the clone

To get the full history we’d need to set the strategy to auto. The following command creates the GIT repository with all the merged branches.

git tfs clone <TFS_URL> <REPOSITORY_PATH> . --branches=auto --resumable   

Skip the selected merged branches

What if we need to exclude some of the branches - ignore the intermediate changes made in the branch.

There is no parameter in Git-Tfs that would allow to specify which branches to skip. It’s either everything that was merged or nothing. But, it is possible to achieve the desired outcome by following the steps below.

Steps

Let’s assume that we want to exclude the branch history of the Branch4. By looking at the source control history we can see that the branch was merged as part of the changeset 29.

  1. First we need to clone the repository up to the changeset before the merge. The clone command allows to pass the changeset id, which causes the clone operation to skip all the further changesets after the one specified:

    -t, --up-to=VALUE    up-to changeset # (optional, -1 for up to
                            maximum, must be a number, not prefixed with C)
    

    So, we need to invoke the clone command with the changeset id prior to the changeset 29.

    git tfs clone <TFS_URL> <REPOSITORY_PATH> . --branches=auto ^ 
        --resumable --up-to=28 
    
  2. Next, we can fetch the merge changeset using different branching strategy - none, so that the branch history is not retrieved. The fetch command also has the --up-to parameter, so it’s possible to retrieve just this one changeset.

    git tfs fetch --branches=none --up-to=29
    
  3. Then, we can get the rest of the changes. But first, we need to override the Git-Tfs configuration so that the full branch history is retrieved.

    When the fetch command is executed with the branches strategy set to none, Git-Tfs sets the git-tfs.ignore-branches flag to True on the repository. So, we need to reset this flag, otherwise the Git-Tfs will ignore other branches.

    git config git-tfs.ignore-branches False
    

    Once the flag is reset, we can fetch the remaining changesets.

    git tfs fetch --branches=auto
    
  4. The last step is to apply the retrieved changes on the master branch.

    git merge remotes/tfs/default
    

Result

As you can see below, the Git repository contains the intermediate changes made in the branches, except for the Branch4.

Git history after the migration

You can exclude any number of branches using the method described above. But, if you need to skip more than a few, it might be good idea to write a script that would automate the process.

comments powered by Disqus