Last active
January 28, 2017 17:10
-
-
Save neg3ntropy/9c47ee936cfce9dcb725 to your computer and use it in GitHub Desktop.
Promote an "upstream" Git branch by merging it into a "downstream" branch.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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?