|  | # | 
|  | # git-flow -- A collection of Git extensions to provide high-level | 
|  | # repository operations for Vincent Driessen's branching model. | 
|  | # | 
|  | # Original blog post presenting this model is found at: | 
|  | #    http://nvie.com/archives/323 | 
|  | # | 
|  | # Feel free to contribute to this project at: | 
|  | #    http://github.com/nvie/gitflow | 
|  | # | 
|  | # Copyright (c) 2010 by Vincent Driessen | 
|  | # Copyright (c) 2010 by Benedikt Böhm | 
|  | # | 
|  |  | 
|  | # shell output | 
|  | warn() { echo "$@" >&2; } | 
|  | die() { warn "$@"; exit 1; } | 
|  |  | 
|  | # set logic | 
|  | has() { | 
|  | local item=$1; shift | 
|  | echo " $@ " | grep -q " $item " | 
|  | } | 
|  |  | 
|  | # basic math | 
|  | min() { [ "$1" -le "$2" ] && echo "$1" || echo "$2"; } | 
|  | max() { [ "$1" -ge "$2" ] && echo "$1" || echo "$2"; } | 
|  |  | 
|  | # basic string matching | 
|  | startswith() { [ "$1" != "${1#$2}" ]; } | 
|  | endswith() { [ "$1" != "${1#$2}" ]; } | 
|  |  | 
|  | # convenience functions for checking shFlags flags | 
|  | flag() { eval FLAG='$FLAGS_'$1; [ $FLAG -eq $FLAGS_TRUE ]; } | 
|  | noflag() { eval FLAG='$FLAGS_'$1; [ $FLAG -ne $FLAGS_TRUE ]; } | 
|  |  | 
|  | # | 
|  | # Git specific common functionality | 
|  | # | 
|  |  | 
|  | # get all available branches | 
|  | LOCAL_BRANCHES=$(git branch | sed 's/^[* ] //') | 
|  | REMOTE_BRANCHES=$(git branch -r | sed 's/^[* ] //') | 
|  | ALL_BRANCHES="$LOCAL_BRANCHES $REMOTE_BRANCHES" | 
|  |  | 
|  | gitflow_test_clean_working_tree() { | 
|  | if ! git diff --no-ext-diff --ignore-submodules --quiet --exit-code; then | 
|  | return 1 | 
|  | elif ! git diff-index --cached --quiet --ignore-submodules HEAD --; then | 
|  | return 2 | 
|  | else | 
|  | return 0 | 
|  | fi | 
|  | } | 
|  |  | 
|  | gitflow_require_clean_working_tree() { | 
|  | gitflow_test_clean_working_tree | 
|  | result=$? | 
|  | if [ $result -eq 1 ]; then | 
|  | die "fatal: Working tree contains unstaged changes. Aborting." | 
|  | fi | 
|  | if [ $result -eq 2 ]; then | 
|  | die "fatal: Index contains uncommited changes. Aborting." | 
|  | fi | 
|  | } | 
|  |  | 
|  | gitflow_require_local_branch() { | 
|  | if ! has $1 $LOCAL_BRANCHES; then | 
|  | die "fatal: Local branch '$1' does not exist and is required." | 
|  | fi | 
|  | } | 
|  |  | 
|  | gitflow_require_remote_branch() { | 
|  | if ! has $1 $REMOTE_BRANCHES; then | 
|  | die "Remote branch '$1' does not exist and is required." | 
|  | fi | 
|  | } | 
|  |  | 
|  | gitflow_require_branch() { | 
|  | if ! has $1 $ALL_BRANCHES; then | 
|  | die "Branch '$1' does not exist and is required." | 
|  | fi | 
|  | } | 
|  |  | 
|  | gitflow_require_branch_absent() { | 
|  | if has $1 $ALL_BRANCHES; then | 
|  | die "Branch '$1' already exists. Pick another name." | 
|  | fi | 
|  | } | 
|  |  | 
|  | # | 
|  | # gitflow_test_branches_equal() | 
|  | # | 
|  | # Tests whether branches and their "origin" counterparts have diverged and need | 
|  | # merging first. It returns error codes to provide more detail, like so: | 
|  | # | 
|  | # 0    Branch heads point to the same commit | 
|  | # 1    First given branch needs fast-forwarding | 
|  | # 2    Second given branch needs fast-forwarding | 
|  | # 3    Branch needs a real merge | 
|  | # | 
|  | gitflow_test_branches_equal() { | 
|  | commit1=$(git rev-parse "$1") | 
|  | commit2=$(git rev-parse "$2") | 
|  | if [ "$commit1" != "$commit2" ]; then | 
|  | base=$(git merge-base "$commit1" "$commit2") | 
|  | if [ "$commit1" = "$base" ]; then | 
|  | return 1 | 
|  | elif [ "$commit2" = "$base" ]; then | 
|  | return 2 | 
|  | else | 
|  | return 3 | 
|  | fi | 
|  | else | 
|  | return 0 | 
|  | fi | 
|  | } | 
|  |  | 
|  | gitflow_require_branches_equal() { | 
|  | gitflow_require_local_branch "$1" | 
|  | gitflow_require_remote_branch "$2" | 
|  | gitflow_test_branches_equal "$1" "$2" | 
|  | status=$? | 
|  | if [ $status -gt 0 ]; then | 
|  | warn "Branches '$1' and '$2' have diverged." | 
|  | if [ $status -eq 1 ]; then | 
|  | die "And branch '$1' may be fast-forwarded." | 
|  | elif [ $status -eq 2 ]; then | 
|  | # Warn here, since there is no harm in being ahead | 
|  | warn "And local branch '$1' is ahead of '$2'." | 
|  | else | 
|  | die "Branches need merging first." | 
|  | fi | 
|  | fi | 
|  | } | 
|  |  | 
|  | # | 
|  | # gitflow_is_branch_merged_into() | 
|  | # | 
|  | # Checks whether branch $1 is succesfully merged into $2 | 
|  | # | 
|  | gitflow_is_branch_merged_into() { | 
|  | local SUBJECT=$1 | 
|  | local BASE=$2 | 
|  | ALL_MERGES=$(git branch --contains $SUBJECT | sed 's/^[* ] //') | 
|  | has $BASE $ALL_MERGES | 
|  | } | 
|  |  |