Skip to content

Instantly share code, notes, and snippets.

@neg3ntropy
Last active January 28, 2017 17:10
Show Gist options
  • Save neg3ntropy/9c47ee936cfce9dcb725 to your computer and use it in GitHub Desktop.
Save neg3ntropy/9c47ee936cfce9dcb725 to your computer and use it in GitHub Desktop.
Promote an "upstream" Git branch by merging it into a "downstream" branch.
#!/bin/bash -eu
git_promote="$(basename "$0" | sed -e 's/-/ /')"
HELP="Usage: $git_promote [options...] [upstream] <downstream>
Promote an \"upstream\" Git branch by merging it into a \"downstream\" branch.
When omitted, the currently checked out branch is used as upstream.
Options:
-m <message> # merge commit message, asked otherwise
--dry-run # echo git commands, do not execute them
--nopull # do not pull from remote
--nopush # do not push from remote
--local # same as --nopull and --nopush
--help # prints this
Examples:
$git_promote qa # promotes current branch to \"qa\"
$git_promote qa prod # promotes \"qa\" branch to \"prod\"
"
# to install copy to /usr/local/bin and
# sudo chmod +x /usr/local/bin/git-promote
# to install man page so that git(no dash)promote --help works:
# mkdir -p /usr/local/man/man1
# git-promote --help | txt2man -t git-promote | gzip | sudo tee /usr/local/man/man1/git-promote.1.gz >/dev/null
git='git'
commit_opts=''
pull_upstream='y'
pull_downstream='y'
push='y'
OPTS=$(getopt -o "m:" \
-l dry-run \
-l local \
-l nopull \
-l nopush \
-l help \
-- "$@") || (echo "$HELP" >&2 ; exit 1)
eval set -- "$OPTS"
while [ $1 != "--" ]; do
case "$1" in
-m)
shift
commit_opts="-m \"$1\""
;;
--dry-run)
git="echo git"
;;
--nopull)
pull_upstream='n'
pull_downstream='n'
;;
--nopush)
push='n'
;;
--local)
pull_upstream='n'
pull_downstream='n'
push='n'
;;
--help)
echo "$HELP"
exit 0
;;
esac
shift
done
shift # eat "--"
current="$(git branch | awk '/^[*]/{print $2;}')"
case "$#" in
1)
upstream="$current"
downstream="$1"
;;
2)
upstream="$1"
downstream="$2"
;;
*)
echo "$HELP" >&2
exit 1
;;
esac
if [ -z "$current" ]; then
exit 1
fi
function fail {
$git checkout "$current" 2>/dev/null || true
exit 1
}
trap 'fail' ERR INT TERM
if [ "$upstream" != "$current" ]; then
$git checkout "$upstream"
else
echo "Promoting $upstream to $downstream"
fi
if [ "$pull_upstream" == 'y' ]; then
$git pull --ff-only
fi
$git checkout "$downstream"
if [ "$pull_downstream" == 'y' ]; then
$git pull --ff-only
fi
$git merge "$upstream" --no-ff $commit_opts
if [ "$push" == 'y' ]; then
$git push
fi
$git checkout "$current"
exit 0
# vim: set expandtab ts=2 sw=2
#!bash
# bash completion for git-promote.
# install as /etc/bash_completion.d/git-promote-completion.bash
__git_promote_list_branches() {
local nomerged=''
if [[ ! -z "$1" ]]; then
nomerged="--no-merged $1"
fi
git branch --list -r --no-color $nomerged 2> /dev/null \
| sed 's/^ *//g' \
| grep "^$origin/" \
| grep -v 'HEAD' \
| sed "s,^$origin/,," \
| sort
}
__git_promote_parse_args_opts() {
while [[ $# > 0 ]] ; do
if [[ "$1" = -* ]]; then
opts=("${opts[@]}" "$1")
if [[ "$1" == '-m' ]]; then
shift
fi
else
args=("${args[@]}" "$1")
fi
shift
done
}
_git_promote() {
local OPTS=(
'--dry-run'
'--help'
'--local'
'-m'
'--nopull'
'--nopush'
)
local cur="${COMP_WORDS[$COMP_CWORD]}"
local args=()
local opts=()
__git_promote_parse_args_opts "${COMP_WORDS[@]:2:$COMP_CWORD-2}"
if [[ "$cur" = -* ]]; then
local avail_opts=$(comm -23 \
<(printf '%s\n' "${OPTS[@]}") \
<(printf '%s\n' "${opts[@]}" | sort -u))
__gitcomp "$avail_opts"
elif [[ ${#args[@]} -lt 2 ]]; then
local origin='origin'
local from=''
if [[ ${#args[@]} -gt 0 ]]; then
from="$origin/${args[0]}"
fi
__gitcomp "$(__git_promote_list_branches "$from")"
else
COMPREPLY=()
fi
}
@gpiccinni
Copy link

Very handy when keeping multiple branches in parallel.

It doesn't work on all systems as BSD implementation of 'getopt' does not support parsing long options, therefore it might fail on FreeBSD, OS X, OpenBSD.

How about replacing long options with short ones or replacing 'getopt' with 'getopts' which is consistent across all environments?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment