question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Is there a command that can be run to get the TFS remote for a Git branch, if any?

See original GitHub issue
  • I have read the documentation about command line options and advanced use cases
  • upgrade and test with the last version
  • specify the version you are using
  • include steps you followed to reproduce the problem
  • if the problem occurs when using a git-tfs command, please provide the output of the command when using the --debug command line option (providing a gist could be a clever idea 😉)

So, I’ve been looking all around the documentation for a while to find what I’m looking for. There are some commands which seem to accomplish what I work, but it requires I have some information “up front”, which, in a scripted scenario, I just might not have.

I’m currently using v0.25.0 of Git-TFS.

I’m trying to determine what the Git-TFS TFS remote is for an arbitrary branch. Check out the scenario below. Assume that I have cloned the root of my TFS Project.

$ git tfs branch --init $/MyTFSProject/Feature/My-Cool-Feature
# I believe this puts me on a git branch Feature/My-Cool-Feature. If not, assume I checked it out now
$ git branch Feature/foo-bar Feature/My-Cool-Feature
$ git checkout Feature/foo-bar
$ git tfs bootstrap
commit abc123def456...
Author: Joe Blow <joe.blow@somedomain.com>
Date: Sun Jan 01 00:00:00 +00:00

    my commit message

    work-items: #12345
    git-tfs-id: [http://url-to-tfs:8080/tfs/MyTFSProjectCollection]$/MyTFSProject/Feature/My-Cool-Feature;C6789

-> existing remote Feature/My-Cool-Feature (up to date)

$ git tfs branch
...
Feature/My-Cool-Feature -> http://url-to-tfs:8080/tfs/MyTFSProjectCollection $/MyTFSProject/Feature/My-Cool-Feature
        refs/remotes/tfs/Feature/My-Cool-Feature - abc123def456... @ 6789

So, in the output of git tfs branch above, it only shows the one branch as being “tied” to the TFS remote. It does not output the fact that the branch Feature/foo-bar is also “bootstrapped” to the TFS remote tfs-remote.Feature/My-Cool-Feature.

Now, I could just issue an additional git tfs bootstrap command. This should be a no-op since the branch is already bootstrapped–but I really shouldn’t depend on that being the case. For example, in a scripted scenario (which is what I’m trying to accomplish), if the git branch is not bootstrapped, I don’t necessarily want to bootstrap it (if it’s even possible)–that may not be what the user wants. So I can’t really use this command to obtain the output I desire because of unintended side effects (i.e. that’s really not what git tfs bootstrap was made for).

Trolling around the .git dir, I was looking for any kind of files that would contain this tracking information. How does Git-TFS know, in this instance, that Feature/foo-bar is “tracking” refs/remotes/tfs/Feature/My-Cool-Feature? (Is it parsing the reflog? If so, it appears it may be stopping at the first successful match.)

If this feature does not exist, please consider this a feature request to add a command to Git-TFS:

As a git-tfs user, I want to be able to issue a command to determine which TFS remote a git branch is tracking So that I can perform scripted operations against the git branch and the TFS remote

Issue Analytics

  • State:open
  • Created 7 years ago
  • Comments:10 (10 by maintainers)

github_iconTop GitHub Comments

1reaction
fourpastmidnightcommented, Oct 6, 2016

My colleagues and I have created a script that allow us to set and then get this information, modeled after the standard git-remote command. We also have an automated script that allows us to maintain a shared git repository with TFS that my team uses in our organization. These scripts assume you’ve cloned extra metadata from your TFS VCS and that you’re using an authors file. Hopefully someone finds these useful.

Here’s git-tfs-remote.sh:

# git-tfs-remote.sh
#!/bin/sh

ME=$(basename "$0")

usage () {
        cat <<EOF

Usage: $ME [-h|--help] | -v[erbose] ( bootstrap | add [<TFS Remote Name>] )

  Options
  =======

  -h, -help

    Show this usage text

  -v
  --verbose

        Be a little more verbose and show the TFS repository name and url after
        the TFS remote name. NOTE: This option must be placed before any
        sub-commands.


  Commands
  ========

  bootstrap

        Uses Git-TFS to bootstrap the current branch with a TFS branch and then
        updates your repository configuration with the bootstrapped TFS remote
        name so that you can use git-tfs-sync.


  add [<TFS Remote Name>]

        Adds a TFS remote for the currently checked out branch, but does not
        bootstrap the branch with Git-TFS. This is useful when the branch has
        already been bootstrapped by Git-TFS and you now want to be able to use
        the git-tfs-sync command. Before you can use the git-fs-sync command,
        configuration must be added about the Git-TFS remote to be used for
        synchronization.

        When running this command without specifying the name of a TFS remote
        tracking branch, the name of the current branch will be used in an 
        attempt to detect the name of a Git-TFS remote to track. If a Git-TFS
        remote is found, additional configuration entries for the local
        repository will be made so that git-tfs-sync can be used. If no TFS
        remote can be found with the name of the current branch, an error will
        be returned. In this case, you must specify a <TFS Remote Name>.

        When you specify the name of a TFS remote, this command will add the
        specified TFS remote for the current branch.

        WARNING: Specifying <TFS Remote Name> assumes you know what you're
                 you're doing and does not attempt to make sure that the TFS
                 remote should or can be added to the current branch. The name
                 you specify will be added to the repository configuration for
                 use with git-tfs-sync.

EOF
        exit 1
}

die () {
        echo "$*" >&2
        exit 1
}

add_git_tfs_remote () {
        git config --local git-tfs-branch."$1".remote "$2" || die "
$(tput setaf 1)ERROR: Unable to update local repository configuration to record
       the TFS remote for '$1'.$(tput sgr0)
"
}

get_tfs_remote_info () {
        echo "$(git config --local --get tfs-remote."$1".$2)"
}

display_tfs_remote_info() {
        TFS_REMOTE_NAME="$(git config --local --get git-tfs-branch."$1".remote)"

        test -n TFS_REMOTE_NAME || die "
This branch is not tracking any TFS remotes.
"

        echo -e "$TFS_REMOTE_NAME\t$(get_tfs_remote_info "$TFS_REMOTE_NAME" url) (url)"
        echo -e "$TFS_REMOTE_NAME\t$(get_tfs_remote_info "$TFS_REMOTE_NAME" repository) (repository)"
}

FOUND_GIT_TFS="f"
VERBOSE="f"
OPERATION=
BRANCH=
TFS_REMOTE_NAME=

FOUND_GIT_TFS="$(which git-tfs)" && test ! "$FOUND_GIT_TFS" = "f" || die "
$(tput setaf 1)ERROR: git-tfs could not be found. Please ensure you installed git-tfs and that
git-tfs.exe is in your PATH.$(tput sgr0)
"
BRANCH="$(git rev-parse --abbrev-ref  HEAD)"

for arg
do
    case $1 in
                bootstrap)
                        OPERATION="$1"
                        shift
                        ;;
                add)
                        OPERATION="$1"
                        shift
                        test $# = 0 || {
                                TFS_REMOTE_NAME="$1" && \
                                shift
                        }
                        ;;
                -v|--verbose)
                        VERBOSE="t"
                        shift
                        ;;
                -h|-help)
                        usage
    esac
done

test -z "$OPERATION" || {
        case $OPERATION in
                add)
                        # If no arguments are given, check to see if there's a TFS remote with the same
                        # name as the current branch. If so, then use the current branch name as the
                        # TFS remote name.
                        test -n "$TFS_REMOTE_NAME" || {
                                TFS_REMOTE_NAME="$BRANCH"
                                get_tfs_remote_info "$$TFS_REMOTE_NAME" repository >/dev/null || die "
$(tput setaf 1)ERROR: Unable to find a TFS remote named:$(tput sgr0)

    $(tput setaf 12)$TFS_REMOTE_NAME$(tput sgr0)

If your local branch name is different than the name of the TFS remote branch
you're trying to track, please specify the name of the TFS branch to add as a
remote tracking branch. 

See '$ME -help' for more information.
"
                        }
                        ;;

                bootstrap)
                        TFS_REMOTE_NAME="$(git tfs bootstrap | grep "existing remote" | sed -e 's|.*remote \(.*\)\( (up to date)\)|\1|')"
                        test -n "$TFS_REMOTE_NAME" || die "
$(tput setaf 1)ERROR: Unable to bootstrap '$BRANCH'$(tput sgr0)
"
                        ;;
        esac

        add_git_tfs_remote "$BRANCH" "$TFS_REMOTE_NAME" 
} && test "$VERBOSE" = "f" && echo "$(git config --local --get git-tfs-branch."$BRANCH".remote)" || display_tfs_remote_info "$BRANCH"  

exit 0

And here’s git-tfs-sync.sh:

#!/bin/sh

ME=$(basename "$0")

usage () {
        cat <<EOF

Usage: $ME [-h|--help] [-v]

  Options
  =======
  -h, --help
    Show this usage text

  -v
    Verbose. Show extra output to aid in debugging.

  This command will ensure that a Git branch which has a corresponding TFS
  remote is synchronized with TFS and the branch's Git remote in the correct
  order to prevent Git commit hash sequencing problems.

  Whenever you need to update a local Git branch which has a corresponding TFS
  remote, use this command instead of the standard fetch or pull commands or
  even Git-TFS fetch or pull commands.

  If the sequence of fetches or pulls is not performed in the correct order,
  the effect would be the same as rebasing a public, shared Git branch,
  possibly causing others to lose work or not be able to synchronize with the
  Git remote.

EOF
        exit 1
}

die () {
        echo "$*" >&2
        exit 1
}

write_info () {
        echo "
$(tput setaf 14)$*$(tput sgr0)"
}

not_rebasing() {
        local retVal;
        test ! -d "${GIT_DIR:-.git}"/rebase-apply
        retVal=$?
        exit $retVal
}

get_upstream() {
        test $# = 2 || exit 1

        case $1 in
                --remote|-r)
                        echo "$2" | sed -e 's|\([^/]*\)/\(.*\)|\1|' ;;
                --branch|-b)
                        echo "$2" | sed -e 's|\([^/]*\)/\(.*\)|\2|' ;;
        esac
}

FOUND_GIT_TFS="f"
VERBOSE="f"
BRANCH=
BRANCH_UPSTREAM=
BRANCH_TFS=
REBASING_MSG="
$(tput setaf 1)ERROR: Rebase in progress. Please finish the rebase operation in progress or
abort the rebase and try again.$(tput sgr0)
"

for arg
do
    case $1 in
            -h|-help)
                    usage
                    ;;
        -v)
            VERBOSE="t"
            shift
            ;;
    esac
done

test $# = 0 || usage

FOUND_GIT_TFS="$(which git-tfs)" && test ! "$FOUND_GIT_TFS" = "f" || die "
$(tput setaf 1)ERROR: git-tfs could not be found. Please ensure you installed git-tfs and that
git-tfs.exe is in your PATH.$(tput sgr0)
"

# This is here just to add some separation between the script invocation
# and any script output.
echo

BRANCH="$(git rev-parse --abbrev-ref HEAD)"
BRANCH_TFS=$(git config --local --get tfs-remote."$(git config --local --get git-tfs-branch."$BRANCH".remote)".repository) || die "
$(tput setaf 1)ERROR: A Git-TFS remote could not be found for this branch.$(tput sgr0)
Did you forget to issue a $(tput setaf 15)'git-tfs-remote add'$(tput sgr0) command on '$BRANCH'?
"
BRANCH_UPSTREAM="$(git rev-parse --abbrev-ref "$BRANCH"@{u})"

test -n "$(get_upstream -b "$BRANCH_UPSTREAM")" || die "$(tput setaf 1)ERROR: No Git remote tracking branch found.$(tput sgr0)
If the Git-TFS branch you're trying to synchronize is not shared on a
centralized Git server, simply use 'git-tfs-fetch -r -x' or
'git-tfs-pull -r -x' instead.

Otherwise, please issue the following command to setup a remote tracking branch:

    git branch --set-upstream-to=<remote_name>/<remote_branch_name>

For example:

    git branch --set-upstream-to=origin/feature/my-topic-branch

"

test "$VERBOSE" = "f" && test "$BRANCH" = "$(get_upstream -b "$BRANCH_UPSTREAM")" || \
cat <<EOF
Branch Information
===============================================================================
Branch name:            $BRANCH
Upstream branch remote: $(get_upstream -r "$BRANCH_UPSTREAM")
Upstream branch name:   $(get_upstream -b "$BRANCH_UPSTREAM")
TFS Remote:             $BRANCH_TFS

EOF

test "$BRANCH" = "$(get_upstream -b "$BRANCH_UPSTREAM")" || (
        CONTINUE=n
        read -n 1 -p "
$(tput setaf 11)WARNING:$(tput sgr0) Your local branch name:

        $(tput setaf 10)'$BRANCH'$(tput sgr0)

    is different than the remote tracking branch name:

        $(tput setaf 9)'$BRANCH_UPSTREAM'$(tput sgr0)

Please ensure the branch information above is correct before continuing.

$(tput setaf 15)Do you want to continue synchronization?$(tput sgr0) [y|$(tput setaf 11)N$(tput sgr0)] ? " CONTINUE

        case "$CONTINUE" in
                y|Y)    echo
                        exit 0
                        ;;
                *)
                        exit 1
                        ;;
        esac
) || die "

$(tput setaf 1)Synchronization canceled.$(tput sgr0)
"

# Update the local copy of the destination branch from the git server
(write_info "Updating '$BRANCH' with any upstream commits" &&
        (
                git fetch && \
                git rebase "$BRANCH_UPSTREAM" && \
                not_rebasing
        ) || die "$REBASING_MSG"
) || die

# Update the local copy of the destination branch with any changesets in TFS but not in git
(write_info "Updating '$BRANCH' with any new changesets from '$BRANCH_TFS'" && \
        (
                git tfs pull -x -r && \
                not_rebasing
        ) || die "$REBASING_MSG"
) || die

# At this point we can minimally push the new TFS changes to origin
(write_info "Updating '$BRANCH_UPSTREAM' with any new commits on '$BRANCH'" && \
        git push $(get_upstream -r "$BRANCH_UPSTREAM") "$BRANCH":"$(get_upstream -b "$BRANCH_UPSTREAM")" refs/notes/*:refs/notes/*
) || die

exit

And here’s git-tfs-merge.sh (NOTE: this needs to be refactored to use git-tfs-sync.sh to remove a lot of duplicate code. We wrote git-tfs-merge.sh first before realizing we needed a way to associate git branches with TFS remotes.):

#!/bin/sh

ME=$(basename "$0")

usage () {
        cat <<EOF

Usage: $ME <destination_branch>

  This command merges the currently checked out git branch, whose parent is a
  branch associated with a TFS remote, to <destination_branch> using the
  Git-TFS rcheckin command.

  This script will peform the following actions:

    1. Ensures <destination_branch> is a branch associated with a Git-TFS TFS
       remote.
    2. Ensures your local copy of <destination_branch> is up-to-date with TFS
         - Any changes brought down will be pushed to <destination_branch>'s
           remote tracking branch.
    3. If <destination_branch> was updated, the current branch will be rebased
       on top of <destination_branch>
    4. Your branch's commits will be replayed to the TFS remote for
       <destination_branch> as TFS changesets
    5. Your local copy of <destination_branch> will be updated from TFS again
    6. The new changesets will be pushed to the remote tracking branch for
       <destination_branch>
    7. The local branch you merged will be deleted
    8. The remote tracking branch associated with your local branch will be
       deleted.

EOF
        exit 1
}

die () {
        test $# -gt 0 || echo "$(tput setaf 1)Failed to merge '$SRC_BRANCH' into '$DEST_BRANCH'.$(tput sgr0)" >&2 && echo "$*" >&2
        exit 1
}

write_info () {
        echo "
$(tput setaf 14)$*$(tput sgr0)"
}

write_warning () {
        echo "
$(tput setaf 11)$*$(tput sgr0)" >&2
}

not_rebasing() {
        local retVal;
        test ! -d "${GIT_DIR:-.git}"/rebase-apply
        retVal=$?
        exit $retVal
}

get_upstream() {
        test $# = 2 || exit 1

        case $1 in
                --remote|-r)
                        echo "$2" | sed -e 's|\([^/]*\)/\(.*\)|\1|' ;;
                --branch|-b)
                        echo "$2" | sed -e 's|\([^/]*\)/\(.*\)|\2|' ;;
        esac
}

test $# = 1 || usage

FOUND_GIT_TFS=
SRC_BRANCH=
SRC_BRANCH_UPSTREAM=
DEST_BRANCH=
DEST_BRANCH_UPSTREAM=
DEST_BRANCH_TFS=
REBASING_MSG="
$(tput setaf 1)ERROR: Rebase in progress. Please finish the rebase operation in progress or
abort the rebase and try again.$(tput sgr0)
"

case $1 in
        -h|-help)
                usage
                ;;
        *)
                FOUND_GIT_TFS="$(which git-tfs)" && test -n "$FOUND_GIT_TFS" || die "
$(tput setaf 1)ERROR: git-tfs could not be found. Please ensure you installed git-tfs and that
git-tfs.exe is in your PATH.$(tput sgr0)
"
                DEST_BRANCH_TFS=$(git config --local --get tfs-remote."$(git config --local --get git-tfs-branch."$1".remote)".repository) || die "
$(tput setaf 1)ERROR: '$1' is not associated with a Git-TFS remote.$(tput sgr0)
Did you forget to issue a $(tput setaf 13)'git tfs bootstrap'$(tput sgr0) command on '$1'?
See '$ME -help' for more information.
"
                SRC_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
                SRC_BRANCH_UPSTREAM="$(git rev-parse --abbrev-ref "$SRC_BRANCH"@{u})"
                DEST_BRANCH="$1"
                DEST_BRANCH_UPSTREAM="$(git rev-parse --abbrev-ref "$DEST_BRANCH"@{u})"
                echo
                ;;
esac

test -n "$(get_upstream -b "$SRC_BRANCH_UPSTREAM")" || die "$(tput setaf 1)ERROR: '$SRC_BRANCH' is not tracking a remote branch.$(tput sgr0)
Please issue the following command to setup a remote tracking branch for
'$SRC_BRANCH':

    git branch --set-upstream-to=<remote_name>/<remote_branch_name>

For example:

    git branch --set-upstream-to=origin/feature/my-topic-branch

"

test ! "$SRC_BRANCH" = "$DEST_BRANCH" || die "$(tput setaf 1)ERROR: Cannot merge '$DEST_BRANCH' to '$DEST_BRANCH_TFS'$(tput sgr0)"

cat <<EOF
Branch Information
===============================================================================
Local source branch name:           $SRC_BRANCH
Upstream source branch remote:      $(get_upstream -r "$SRC_BRANCH_UPSTREAM")
Upstream source branch name:        $(get_upstream -b "$SRC_BRANCH_UPSTREAM")

Local destination branch name:      $DEST_BRANCH
Upstream destination branch remote: $(get_upstream -r "$DEST_BRANCH_UPSTREAM")
Upstream destination branch name:   $(get_upstream -b "$DEST_BRANCH_UPSTREAM")
Destination branch TFS remote:      $DEST_BRANCH_TFS
EOF

test "$SRC_BRANCH" = "$(get_upstream -b "$SRC_BRANCH_UPSTREAM")" || (
        CONTINUE=n
        read -n 1 -p "
$(tput setaf 11)WARNING:$(tput sgr0) Your local branch name:

        $(tput setaf 10)'$SRC_BRANCH'$(tput sgr0)

    is different than the remote tracking branch name:

        $(tput setaf 9)'$SRC_BRANCH_UPSTREAM'$(tput sgr0)

Please ensure the branch information above is correct before continuing.

$(tput setaf 15)Do you want to continue merging?$(tput sgr0) [y|$(tput setaf 11)N$(tput sgr0)] ? " CONTINUE

        case "$CONTINUE" in
                y|Y)    echo
                        exit 0
                        ;;
                *)
                        exit 1
                        ;;
        esac
) || die "

$(tput setaf 1)Merging canceled.$(tput sgr0)
"

# Update the local copy of the destination branch from the git server
(write_info "Updating '$DEST_BRANCH' with any upstream commits" &&
        (
                git checkout "$DEST_BRANCH" && \
                git fetch && \
                git rebase "$DEST_BRANCH_UPSTREAM" && \
                not_rebasing
        ) || die "$REBASING_MSG"
) || die

# Update the local copy of the destination branch with any changesets in TFS but not in git
(write_info "Updating '$DEST_BRANCH' with any new changesets from '$DEST_BRANCH_TFS'" && \
        (
                git tfs pull -x -r && \
                not_rebasing
        ) || die "$REBASING_MSG"
) || die

# At this point we can minimally push the new TFS changes to origin
(write_info "Updating '$DEST_BRANCH_UPSTREAM' with any new commits on '$DEST_BRANCH'" && \
        git push $(get_upstream -r "$DEST_BRANCH_UPSTREAM") "$DEST_BRANCH":"$(get_upstream -b "$DEST_BRANCH_UPSTREAM")" refs/notes/*:refs/notes/*
) || die

# Rebase the local topic branch on top of the local copy of the destination branch
(write_info "Rebasing '$SRC_BRANCH' on '$DEST_BRANCH' and updating '$SRC_BRANCH_UPSTREAM'" &&
        (
                git checkout "$SRC_BRANCH" && \
                git rebase "$DEST_BRANCH" && \
                not_rebasing && \
                git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") +"$SRC_BRANCH":"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
        ) || die "$REBASING_MSG"
) || die

# Replay each commit and checkin each commit to TFS
(write_info "Checking in '$SRC_BRANCH' to '$DEST_BRANCH_TFS'" && git tfs rcheckin) || die

# Rebase the local copy of the destination branch on top of the remote TFS branch
write_info "Pulling from '$DEST_BRANCH_TFS' into '$DEST_BRANCH'" &&
(
        git checkout "$DEST_BRANCH" && \
        git tfs pull -x -r && \
        not_rebasing
) || \
die "$(write_warning "WARNING: Encountered an error while pulling from '$DEST_BRANCH_TFS'.
The branch '$SRC_BRANCH' was successfully merged into '$DEST_BRANCH'.
However, no other clean up operations will be performed.
Please resolve the issue and run the following commands:

    $ git tfs pull -x -r
    $ git push $(get_upstream -r "$DEST_BRANCH_UPSTREAM") "$DEST_BRANCH":"$(get_upstream -b "$DEST_BRANCH_UPSTREAM")" refs/notes/*:refs/notes/*
    $ git checkout "$SRC_BRANCH"
    $ git rebase "$DEST_BRANCH"
    $ git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") +"$SRC_BRANCH":"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
    $ git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") :"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
    $ git branch -d "$SRC_BRANCH"
")"

# Push the updated local copy of the destination branch to the Git server
(write_info "Updating '$DEST_BRANCH_UPSTREAM' with '$DEST_BRANCH'" && \
        git push $(get_upstream -r "$DEST_BRANCH_UPSTREAM") "$DEST_BRANCH":"$(get_upstream -b "$DEST_BRANCH_UPSTREAM")" refs/notes/*:refs/notes/*
) || \
die "$(write_warning "WARNING: Encountered an error while pushing '$DEST_BRANCH'
to '$DEST_BRANCH_UPSTREAM' or while pushing refs/notes/*.
The branch '$SRC_BRANCH' was successfully merged into '$DEST_BRANCH'.
However, no other clean up operations will be performed.
Please ensure everything is OK and then run the following commands:

    $ git push $(get_upstream -r "$DEST_BRANCH_UPSTREAM") "$DEST_BRANCH":"$(get_upstream -b "$DEST_BRANCH_UPSTREAM")" refs/notes/*:refs/notes/*
    $ git checkout "$SRC_BRANCH"
    $ git rebase "$DEST_BRANCH"
    $ git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") +"$SRC_BRANCH":"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
    $ git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") :"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
    $ git branch -d "$SRC_BRANCH"
")"

(write_info "Rebasing '$SRC_BRANCH' onto '$DEST_BRANCH' so that the Pull Request shows as
MERGED on the Git server" && \
        git checkout "$SRC_BRANCH" && \
        git rebase "$DEST_BRANCH" && \
        not_rebasing
) || \
die "$(write_warning "WARNING: Unable to rebase '$SRC_BRANCH' onto '$DEST_BRANCH'.
The branch '$SRC_BRANCH' was successfully merged into '$DEST_BRANCH'.
However, no other clean up operations will be performed.
Please abort or resolve the rebase operation in progress. Once the issue with the
rebase has been resolved, please run the following commands:

    # Run this command if you're not already on $SRC_BRANCH.
    $ git checkout "$SRC_BRANCH"

    # Run this command ONLY if you aborted the rebase.
    $ git rebase "$DEST_BRANCH"

    # Run the next three commands to clean up the branches
    $ git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") +"$SRC_BRANCH":"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
    $ git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") :"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
    $ git branch -d "$SRC_BRANCH"
")"

(write_info "Pushing '$SRC_BRANCH' to '$SRC_BRANCH_UPSTREAM'" && \
        git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") +"$SRC_BRANCH":"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
) || \
die "$(write_warning "WARNING: Unable to push '$SRC_BRANCH' to '$SRC_BRANCH_UPSTREAM'.
The branch '$SRC_BRANCH' was successfully merged into '$DEST_BRANCH'.
However, no other clean up operations will be performed.
Please investigate why '$SRC_BRANCH' could not be pushed to
'$SRC_BRANCH_UPSTREAM' and resolve the issue.
Once the issue has been resolved, please run the following commands:

    $ git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") +"$SRC_BRANCH":"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
    $ git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") :"$(get_upstream -b "$SRC_BRANCH_UPSTREAM")"
    $ git branch -d "$SRC_BRANCH"
")"

(write_info "Deleting '$SRC_BRANCH'" && \
        git checkout "$DEST_BRANCH" && \
        git branch -d "$SRC_BRANCH"
) || \
write_warning "WARNING: Unable to delete '$SRC_BRANCH'."

(write_info "Deleting '$SRC_BRANCH_UPSTREAM'" && \
        git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") :"$SRC_BRANCH"
) || \
write_warning "WARNING: Unable to delete the remote branch '$SRC_BRANCH_UPSTREAM'.
Please ensure everything is OK and then run the following command:

    git push $(get_upstream -r "$SRC_BRANCH_UPSTREAM") :\"$SRC_BRANCH\"
"

echo "
$(tput setaf 10)SUCCESS: Checked in '$SRC_BRANCH' to '$DEST_BRANCH_TFS',
updated '$DEST_BRANCH',
and '$DEST_BRANCH_UPSTREAM'.$(tput sgr0)
"
0reactions
fourpastmidnightcommented, Aug 5, 2016

@pmiossec Thanks for the explanations. OK, that makes sense you’re not using the ref-log. And I get what you’re doing. I guess I still don’t 100% understand why you can’t say a Git branch “tracks” a TFS remote.

Anyway, let me tell you what we’re doing.

We have a TFS Team Project that is fairly large (it took 26 hours to clone, anyway). I am on a 3-person team (and we’re one team out of 6) that are using this Git repository. The rest of the teams use TFS directly (our team really just likes the simplicity of Git, so we’re the “odd man out”).

OK, so what I did was clone the TFS repository. Then I pushed my repo’s branches up to an on-prem Atlassian Stash server so that the other two team members could clone from that. (We have this all figured out, and it’s working great. When I get around to it, I’m going to blog on it–perhaps even submit some documentation here on the process and how we work.) However, yesterday we ran into a bit of a problem–partly because we didn’t have a full understanding of what was going on; we just hadn’t thought everything through. Prior to yesterday, I was responsible for updating my local repository from TFS, and then updating the Atlassian Stash server that everyone else would then pull from. But, as you can imagine, I’m a bottleneck now.

My team is very smart, so there’s no need for me to be a bottle neck. We wrote a script that automated the process to merge a git topic branch back into a parent git feature branch (which is also a Git-TFS branch; i.e. the parent branch is “bootstrapped” to a Git-TFS remote). The script worked beautifully.

Now here’s where I went wrong. I let my copy of the parent branch become behind. (I did this on purpose–I wanted to check that everything was working as I expected). Knowing my local git feature branch was behind Stash and TFS, I pulled from TFS first. I then checked my hashes with the ones up on Stash and they were different! In hindsight, I should’ve expected this. (If any team member knows about a TFS branch in their Git repository that no one else knows about, especially the Stash server, there’s a potential for people’s hashes to not “line up”–and this is expected if you know what’s going on under the covers.)

What we learned was that, when working with multiple team members who are all updating TFS and Stash, the order in which you fetch/pull from Stash and TFS is important. Always pull from the centralized Stash server first, then pull from TFS; and after pulling from TFS, immediately push back to Stash. Then everyone remains in synch. (Yes, there is still a slight chance for this to go wrong–in this working scenario, you can’t 100% get rid of potential “race conditions”; but since there’s only 3 of us working on a shared TFS/Git branch, the likelihood of this race condition occurring is quite small).

So now I want to write a script that our team would run when “synchronizing” the Git-TFS feature branch so that everyone stays in synch. Here’s the basic outline of what the script would do:

  1. Get the branch’s git upstream remote tracking branch, if any, from Atlassian Stash.
  2. Get the branch’s TFS “tracking” branch if any
    • This is where I need to determine which branch git-tfs-pull would get its changesets/commits from.
    • This is where you say Git-TFS doesn’t have a “tracking” branch, but really, it does. This branch is always pulling from the same TFS “remote”. So in effect, it’s “tracking” the TFS remote branch. Yes, yes, under the covers, it’s not really the same–but the facade you guys created is “close enough”.
  3. Fetch/rebase from origin (i.e. make sure the local copy of the Git-TFS branch is up-to-date with the Atlassian Stash copy)
  4. git-tfs-pull -x -r (Synchronize from TFS)
  5. Immediately push the branch back to Atlassian stash

As part of our process, no one ever commits directly to a branch that is “bootstrapped” to TFS. All work is always done on a topic branch branched off of a “bootstrapped” TFS branch. The only thing that ever commits to a “bootstrapped” TFS branch is git-tfs-rcheckin and git-tfs-pull.

The only time we would need to use the above script is when forward-integrating changes from TFS/Main into TFS/Our-Feature-Branch and needing to “synchronize” our central git server (Atlassian Stash) with these changes.

Why do we use the centralized Git Server? So we can use a git-flow style of working, and then use the Pull Request feature for code reviews. Once the PR is approved, we use our custom “merge” script to rcheckin the changes to the Git-TFS branch and automatically close the PR on Stash. It’s really a sweet setup.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Change default remote for git-tfs repository
I tried to manually edit the url property of the [tfs-remote "default"] so it points to the new address and run every possible...
Read more >
How to find the url for a git-tfs remote - Spin the Moose
For git remotes, the 'git remote –v' command does a great job of showing you the urls that existing remotes map to but...
Read more >
2.5 Git Basics - Working with Remotes
To see which remote servers you have configured, you can run the git remote command. It lists the shortnames of each remote handle...
Read more >
Git command reference - Azure Repos
Right-click your local repo and select Open Command Prompt. Open a command prompt to a repo from inside Visual Studio. Important. Some commands...
Read more >
Source Control with Git in Visual Studio Code
The Git: Create Branch command lets you quickly create a new branch. Just provide the name of your new branch and VS Code...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found