A place for spare thoughts

18/07/2011

How to establish git central repository for working against TFS with git-tfs bridge

Filed under: git, git-tfs — Ivan Danilov @ 17:40

As I described here previously my goal was to establish central git repository and avoid redundant round-trips to TFS whenever possible.

To achieve this now you probably want to follow my advise in the above mentioned article about having user.name=<tfs account name without domain> and same user.email for everyone fetching changes from TFS.
In the latest git-tfs sources this was already fixed, so you don’t need to set this kind of things.

When I established central repository I faced some inconveniences: firstly pattern “checkout master, check central repository for changes already there but not in your local repository, pull new changes from TFS, push to central repository if anything new was pulled, checkout old working branch again, optionally rebase it onto master” was very boring and very repeatable. And the second inconvenience: this pattern should be repeated each time something new appears in TFS. I want to have some scheduled updating so I wouldn’t think about such things as when and how I should update latest version etc.

Well, it is perfect target for automation. So now I want to share my bash script that does these things and saves you several dozens of key-pressing each time you need get changes from TFS.

#!/bin/sh

check_err()
{
    # parameter 1 is last exit code
    # parameter 2 is error message that should be shown if error code is not 0
    if [ "${1}" -ne "0" ]; then
        cat '~temp.log'
        echo ${2}
        rm -f '~temp.log' &gt; /dev/null
        exit ${1}
    fi;
    rm -f '~temp.log' &gt; /dev/null
}

echo "$(date) Update launched"

if [ ! -z "$(git status --porcelain)" ]; then
    echo "$(date) Your status is not clean, can't update"
    exit 1;
fi;

branch_name="$(git symbolic-ref HEAD 2&gt;/dev/null)"
branch_name=${branch_name##refs/heads/}

if [ ! "$branch_name" == "master" ]; then
    git checkout master
fi;

echo "$(date) Pulling from central repo first to avoid redundant round-trips to TFS..."
git pull &gt; '~temp.log'
check_err $? "Pulling from central repo failed"

echo "$(date) Pulling from TFS..."
git tfs pull -d &gt; '~temp.log'
check_err $? "Pulling from TFS resulted in error";

remote_conflicting_commits="$(git rev-list origin/master ^master)"
if [ ! -z "$remote_conflicting_commits" ]; then
    echo "origin/master has conflicting commits, can't push"
    exit 1;
fi;

local_commits_to_push="$(git rev-list master ^origin/master)"
if [ -z "$local_commits_to_push" ]; then
    echo "$(date) Central repo is up-to-date, nothing to push"
else
    echo "$(date) Pushing updates to central repo"
    git push --tags origin master &gt; '~temp.log'
    check_err $? "Push to central resulted in error";
fi;

if [ ! "$branch_name" == "master" ]; then
	git checkout $branch_name
	if [ "$1" == "-r" ]; then
		echo "Rebasing $branch_name on master";
		git rebase master
	fi;
fi;

This script assumes you want master branch to mirror TFS and rebases your working branch onto new changes only if you have specified -r switch. And for the second inconvenience you have just to set-up some dedicated working copy and run this script each, say, five minutes in it. It is very easy to do with built-in Windows Task Scheduler:

  1. Go to Start -> Administrative tools -> Task Scheduler
  2. Click Create Task on the right side
  3. Check radio button ‘Run whether user is logged on or not’
  4. Select Triggers tab, click ‘New’. Set Start=’One time’ and ‘Repeat task every’ whatever, check ‘Enabled’, click OK.
  5. Go to Actions tab, ‘New’. Set Program/script to ‘cmd‘, Add arguments=’/c "sh.exe update >> log.txt"‘ and in the Start in field put path to your working copy, dedicated to central repository updating.
    1. That’s all. Now you should have updates regularly without any efforts. It is important to note though, that script assumes your remote named origin/master and noone pushes conflicting changes to central repo’s master branch.

      And not forget to add /log.txt to .gitignore. Otherwise your updates will just fail to start because of not clean working tree.

      Advertisements

Blog at WordPress.com.