#!/bin/bash # # Moves a branch to or from the current git tree to or from # another git tree # # usage: git-branchmove get|put REMOTE BRANCH set -e set -o posix fail () { echo >&2 "git-branchmove: $*"; exit 16; } badusage () { fail "bad usage: $*"; } case "$#.$1" in 3.get) op=get remote="$2" branch="$3" ;; 3.put) op=put branch="$3" ;; *) badusage "wrong number of arguments or wrong operation" ;; esac # Plan of attack: # determine execute-sh runes for src and dst trees # check that source branch is not checked out # list affected branches on source # list affected branches on destination and moan if any nonequal overlap # transfer src->dst refs/heads/BRANCH:refs/heads/BRANCH # transfer and merge reflog(s) xxx todo # delete src refs case "$remote" in *:*) remoteurl="$remote" ;; *) remoteurl="$( git config remote."$remote".pushurl || git config remote."$remote".url || fail "no pushurl or url defined for remote $remote" )" esac remote_spec="$(perl -e ' $_ = $ARGV[0]; if (m#^ssh://([^:/]+)(?:\:(\w+))?#) { print "$'\''|ssh "; print " -p $3" if $2; print "$1\n"; } elsif (m#^([-+_.0-9a-zA-Z\@]+):(?!//)#) { print "$'\''|ssh $1\n"; } else { die "git-branchmove: unsupported remote url \`$_'\''\n"; } ' "$remoteurl")" remote_path="${remote_spec%%|*}" remote_rune="${remote_spec#*|}" case $op in get) src_rune="$remote_rune" src_path="$remote_path" dst_rune="sh -c" dst_path=. ;; put) dst_rune="$remote_rune" dst_path="$remote_path" src_rune="sh -c" src_path=. ;; esac