blob: 4179fde7e3b65068867b6ee217e7a06f1b15aafe [file] [log] [blame]
Benedikt Böhme2fa4912010-01-26 14:41:20 +01001#!/bin/sh
Benedikt Böhm00ccea62010-01-26 12:39:36 +01002#
Vincent Driessen6c2d30b2010-01-26 22:18:36 +01003# git-flow -- A collection of Git extensions to provide high-level
4# repository operations for Vincent Driessen's branching model.
Benedikt Böhm00ccea62010-01-26 12:39:36 +01005#
6# Original blog post presenting this model is found at:
7# http://nvie.com/archives/323
8#
9# Feel free to contribute to this project at:
10# http://github.com/nvie/gitflow
11#
12# Copyright (c) 2010 by Vincent Driessen
13# Copyright (c) 2010 by Benedikt Böhm
14#
15
Benedikt Böhme5eaff92010-01-26 12:44:55 +010016# enable debug mode
17if [ "$DEBUG" = "yes" ]; then
18 set -x
19fi
20
Vincent Driessen58995b52010-01-28 12:39:06 +010021export GIT_DIR=$(git rev-parse --git-dir)
Benedikt Böhm4a864fb2010-01-26 12:59:27 +010022export GITFLOW_DIR=$(dirname "$0")
23export MASTER_BRANCH=$(git config --get gitflow.branch.master || echo master)
24export DEVELOP_BRANCH=$(git config --get gitflow.branch.develop || echo develop)
Benedikt Böhm350e7152010-01-26 13:05:05 +010025export ORIGIN=$(git config --get gitflow.origin || echo origin)
Benedikt Böhm427c5db2010-01-26 18:23:44 +010026export README=$(git config --get gitflow.readme || echo README)
Benedikt Böhm4a864fb2010-01-26 12:59:27 +010027
Benedikt Böhm00ccea62010-01-26 12:39:36 +010028warn() { echo "$@" >&2; }
29die() { warn "$@"; exit 1; }
Benedikt Böhme2fa4912010-01-26 14:41:20 +010030
31has() {
32 local item=$1; shift
33 echo " $@ " | grep -q " $item "
34}
Benedikt Böhm00ccea62010-01-26 12:39:36 +010035
36usage() {
Vincent Driessen186d2b52010-01-27 23:48:39 +010037 echo "usage: git flow <subcommand>"
Benedikt Böhm00ccea62010-01-26 12:39:36 +010038 echo
Vincent Driessen186d2b52010-01-27 23:48:39 +010039 echo "Available subcommands are:"
40 echo " init Initialize a new git repo with support for the branching model."
41 echo " feature Manage your feature branches."
42 echo " release Manage your release branches."
43 echo " hotfix Manage your hotfix branches."
44 echo " support Manage your support branches."
Vincent Driessen3625f392010-01-28 00:13:26 +010045 echo " version Shows version information."
Benedikt Böhm7d703a82010-01-26 13:17:12 +010046 echo
Vincent Driessen186d2b52010-01-27 23:48:39 +010047 echo "Try 'git flow <subcommand> help' for details."
Benedikt Böhm00ccea62010-01-26 12:39:36 +010048}
49
50main() {
Benedikt Böhm427c5db2010-01-26 18:23:44 +010051 if [ $# -lt 1 ]; then
Benedikt Böhm00ccea62010-01-26 12:39:36 +010052 usage
53 exit 1
54 fi
55
Vincent Driessenea58d0f2010-01-30 20:51:03 +010056 # use the shFlags project to parse the command line arguments
57 . "$GITFLOW_DIR/shFlags/src/shFlags"
58 #DEFINE_boolean quiet 0 'run without output' q
59 #DEFINE_boolean verbose 0 'run verbose (more output)' v
60 FLAGS "$@" || exit $?
61 eval set -- "${FLAGS_ARGV}"
62
Benedikt Böhm00ccea62010-01-26 12:39:36 +010063 # sanity checks
Vincent Driessen186d2b52010-01-27 23:48:39 +010064 SUBCOMMAND="$1"; shift
Benedikt Böhm427c5db2010-01-26 18:23:44 +010065
Vincent Driessen186d2b52010-01-27 23:48:39 +010066 if [ ! -e "$GITFLOW_DIR/git-flow-$SUBCOMMAND" ]; then
Benedikt Böhm00ccea62010-01-26 12:39:36 +010067 usage
68 exit 1
69 fi
70
Vincent Driessen2ba9a4d2010-01-27 12:51:07 +010071 if ! git rev-parse --git-dir >/dev/null; then
Benedikt Böhm00ccea62010-01-26 12:39:36 +010072 die "Not a git repository"
73 fi
74
75 # get all available branches
76 LOCAL_BRANCHES=$(git branch | sed 's/^[* ] //')
77 REMOTE_BRANCHES=$(git branch -r | sed 's/^[* ] //')
78 ALL_BRANCHES="$LOCAL_BRANCHES $REMOTE_BRANCHES"
79
80 # run command
Vincent Driessen186d2b52010-01-27 23:48:39 +010081 . "$GITFLOW_DIR/git-flow-$SUBCOMMAND"
Benedikt Böhm00ccea62010-01-26 12:39:36 +010082
Vincent Driessenea58d0f2010-01-30 20:51:03 +010083 #
84 # TODO: How to handle 'git flow feature --verbose'
85 # instead of 'git flow feature list --verbose'
86 # "--verbose" is not a subcommand!
87 #
Vincent Driessen186d2b52010-01-27 23:48:39 +010088 SUBACTION="${1:-default}"; shift
89 if ! typeset -f cmd_$SUBACTION 2>&1 >/dev/null; then
90 warn "Unknown subcommand: '$1'"
91 usage
92 exit 1
Benedikt Böhm427c5db2010-01-26 18:23:44 +010093 fi
94
Vincent Driessen186d2b52010-01-27 23:48:39 +010095 # run the specified action
96 cmd_$SUBACTION "$@"
Benedikt Böhm427c5db2010-01-26 18:23:44 +010097}
98
Vincent Driessen62345d52010-01-29 10:27:01 +010099gitflow_test_clean_working_tree() {
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100100 if ! git diff --no-ext-diff --ignore-submodules --quiet --exit-code; then
Vincent Driessen62345d52010-01-29 10:27:01 +0100101 return 1
102 elif ! git diff-index --cached --quiet --ignore-submodules HEAD --; then
103 return 2
104 else
105 return 0
106 fi
107}
108
109gitflow_require_clean_working_tree() {
110 gitflow_test_clean_working_tree
111 result=$?
112 if [ $result -eq 1 ]; then
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100113 die "Working tree contains unstaged changes. Aborting ..."
114 fi
Vincent Driessen62345d52010-01-29 10:27:01 +0100115 if [ $result -eq 2 ]; then
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100116 die "Index contains uncommited changes. Aborting ..."
117 fi
118}
119
120gitflow_require_local_branch() {
121 if ! has $1 $LOCAL_BRANCHES; then
122 die "Local branch '$1' does not exist and is required."
123 fi
124}
125
126gitflow_require_remote_branch() {
127 if ! has $1 $REMOTE_BRANCHES; then
128 die "Remote branch '$1' does not exist and is required."
129 fi
130}
131
132gitflow_require_branch() {
133 if ! has $1 $ALL_BRANCHES; then
134 die "Branch '$1' does not exist and is required."
135 fi
136}
137
138gitflow_require_branch_absent() {
139 if has $1 $ALL_BRANCHES; then
140 die "Branch '$1' already exists. Pick another name."
141 fi
142}
143
144#
145# gitflow_test_branches_equal()
146#
147# Tests whether branches and their "origin" counterparts have diverged and need
148# merging first. It returns error codes to provide more detail, like so:
149#
150# 0 Branch heads point to the same commit
151# 1 First given branch needs fast-forwarding
152# 2 Second given branch needs fast-forwarding
153# 3 Branch needs a real merge
154#
155gitflow_test_branches_equal() {
156 commit1=$(git rev-parse "$1")
157 commit2=$(git rev-parse "$2")
158 if [ "$commit1" != "$commit2" ]; then
159 base=$(git merge-base "$commit1" "$commit2")
160 if [ "$commit1" = "$base" ]; then
161 return 1
162 elif [ "$commit2" = "$base" ]; then
163 return 2
164 else
165 return 3
166 fi
167 else
168 return 0
169 fi
170}
171
172gitflow_require_branches_equal() {
173 gitflow_require_local_branch "$1"
174 gitflow_require_remote_branch "$2"
175 gitflow_test_branches_equal "$1" "$2"
176 status=$?
177 if [ $status -gt 0 ]; then
178 warn "Branches '$1' and '$2' have diverged."
179 if [ $status -eq 1 ]; then
180 die "And branch '$1' may be fast-forwarded."
181 elif [ $status -eq 2 ]; then
182 # Warn here, since there is no harm in being ahead
183 warn "And local branch '$1' is ahead of '$2'."
184 else
185 die "Branches need merging first."
186 fi
187 fi
188}
189
Vincent Driessen58995b52010-01-28 12:39:06 +0100190#
191# gitflow_is_branch_merged_into()
192#
193# Checks whether branch $1 is succesfully merged into $2
194#
195gitflow_is_branch_merged_into() {
196 local SUBJECT=$1
197 local BASE=$2
198 ALL_MERGES=$(git branch --contains $SUBJECT | sed 's/^[* ] //')
199 has $BASE $ALL_MERGES
200}
201
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100202main "$@"