blob: 2a46a7aa9b5faca537a5ee875ec738fde2b02e92 [file] [log] [blame]
Benedikt Böhm00ccea62010-01-26 12:39:36 +01001#
Vincent Driessen6c2d30b2010-01-26 22:18:36 +01002# git-flow -- A collection of Git extensions to provide high-level
3# repository operations for Vincent Driessen's branching model.
Benedikt Böhm00ccea62010-01-26 12:39:36 +01004#
5# Original blog post presenting this model is found at:
6# http://nvie.com/archives/323
7#
8# Feel free to contribute to this project at:
9# http://github.com/nvie/gitflow
10#
11# Copyright (c) 2010 by Vincent Driessen
12# Copyright (c) 2010 by Benedikt Böhm
13#
14
Vincent Driessen7832d6e2010-02-21 21:31:03 +010015require_git_repo
16require_gitflow_initialized
Vincent Driessend72e4ac2010-02-16 21:33:51 +010017gitflow_load_settings
Benedikt Böhm49dd62b2010-01-28 00:51:15 +010018VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
Vincent Driessenc1598bf2010-02-20 16:52:48 +010019PREFIX=$(git config --get gitflow.prefix.release)
Benedikt Böhm49dd62b2010-01-28 00:51:15 +010020
Benedikt Böhm00ccea62010-01-26 12:39:36 +010021usage() {
Vincent Driessen3c337fb2010-02-04 11:30:18 +010022 echo "usage: git flow release [list] [-v]"
Vincent Driessena2e41162010-02-24 01:37:07 +010023 echo " git flow release start [-F] <version>"
24 echo " git flow release finish [-Fsump] <version>"
Benedikt Böhm00ccea62010-01-26 12:39:36 +010025}
26
Vincent Driessen170dc742010-01-28 00:20:51 +010027cmd_default() {
Vincent Driessenb866b012010-01-28 01:01:53 +010028 cmd_list "$@"
Benedikt Böhm00ccea62010-01-26 12:39:36 +010029}
30
Vincent Driessenb866b012010-01-28 01:01:53 +010031cmd_list() {
Vincent Driessen3c337fb2010-02-04 11:30:18 +010032 DEFINE_boolean verbose false 'verbose (more) output' v
33 parse_args "$@"
34
Vincent Driessenf46e2902010-02-15 23:01:52 +010035 local release_branches
36 local current_branch
37 local short_names
Vincent Driessen7832d6e2010-02-21 21:31:03 +010038 release_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")
Vincent Driessen27592dd2010-02-06 14:45:39 +010039 if [ -z "$release_branches" ]; then
Vincent Driessen170dc742010-01-28 00:20:51 +010040 warn "No release branches exist."
41 exit 0
42 fi
Vincent Driessen3c337fb2010-02-04 11:30:18 +010043
Vincent Driessen27592dd2010-02-06 14:45:39 +010044 current_branch=$(git branch | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g')
Vincent Driessen68845232010-02-10 00:43:21 +010045 short_names=$(echo "$release_branches" | sed "s ^$PREFIX g")
Vincent Driessen27592dd2010-02-06 14:45:39 +010046
Vincent Driessen3c337fb2010-02-04 11:30:18 +010047 # determine column width first
Vincent Driessenf46e2902010-02-15 23:01:52 +010048 local width=0
49 local branch
Vincent Driessen27592dd2010-02-06 14:45:39 +010050 for branch in $short_names; do
Vincent Driessenf46e2902010-02-15 23:01:52 +010051 local len=${#branch}
Vincent Driessen3c337fb2010-02-04 11:30:18 +010052 width=$(max $width $len)
53 done
Vincent Driessenf46e2902010-02-15 23:01:52 +010054 width=$(($width+3))
Vincent Driessen3c337fb2010-02-04 11:30:18 +010055
Vincent Driessenf46e2902010-02-15 23:01:52 +010056 local branch
Vincent Driessen27592dd2010-02-06 14:45:39 +010057 for branch in $short_names; do
Vincent Driessenf46e2902010-02-15 23:01:52 +010058 local fullname=$PREFIX$branch
59 local base=$(git merge-base "$fullname" "$DEVELOP_BRANCH")
60 local develop_sha=$(git rev-parse "$DEVELOP_BRANCH")
61 local branch_sha=$(git rev-parse "$fullname")
Vincent Driessen27592dd2010-02-06 14:45:39 +010062 if [ "$fullname" = "$current_branch" ]; then
Vincent Driessen3c337fb2010-02-04 11:30:18 +010063 printf "* "
64 else
65 printf " "
66 fi
67 if flag verbose; then
68 printf "%-${width}s" "$branch"
69 if [ "$branch_sha" = "$develop_sha" ]; then
70 printf "(no commits yet)"
71 else
Vincent Driessenf46e2902010-02-15 23:01:52 +010072 local nicename=$(git rev-parse --short "$base")
Vincent Driessen3c337fb2010-02-04 11:30:18 +010073 printf "(based on $nicename)"
74 fi
75 else
76 printf "%s" "$branch"
77 fi
78 echo
79 done
Vincent Driessen170dc742010-01-28 00:20:51 +010080}
81
Benedikt Böhm00ccea62010-01-26 12:39:36 +010082cmd_help() {
83 usage
84 exit 0
85}
86
Vincent Driessenb866b012010-01-28 01:01:53 +010087parse_args() {
Vincent Driessen3c337fb2010-02-04 11:30:18 +010088 # parse options
89 FLAGS "$@" || exit $?
90 eval set -- "${FLAGS_ARGV}"
91
92 # read arguments into global variables
Vincent Driessenc5fcc012010-02-10 00:18:08 +010093 VERSION=$1
94 BRANCH=$PREFIX$VERSION
Vincent Driessen3c337fb2010-02-04 11:30:18 +010095}
96
97require_version_arg() {
Vincent Driessenb866b012010-01-28 01:01:53 +010098 if [ "$VERSION" = "" ]; then
Vincent Driessen3c337fb2010-02-04 11:30:18 +010099 warn "Missing argument <version>"
Vincent Driessenb866b012010-01-28 01:01:53 +0100100 usage
101 exit 1
102 fi
Vincent Driessenb866b012010-01-28 01:01:53 +0100103}
104
Vincent Driessen010252a2010-02-04 10:31:29 +0100105require_base_is_on_develop() {
106 if ! git branch --contains "$BASE" 2>/dev/null \
107 | sed 's/[* ] //g' \
108 | grep -q "^$DEVELOP_BRANCH\$"; then
109 die "fatal: Given base '$BASE' is not a valid commit on '$DEVELOP_BRANCH'."
110 fi
111}
112
Vincent Driessen6d64d2c2010-02-16 06:41:13 +0100113require_no_existing_release_branches() {
Vincent Driessen7832d6e2010-02-21 21:31:03 +0100114 local release_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")
Vincent Driessen6d64d2c2010-02-16 06:41:13 +0100115 local first_branch=$(echo ${release_branches} | head -n1)
116 first_branch=${first_branch#$PREFIX}
117 [ -z "$release_branches" ] || \
118 die "There is an existing release branch ($first_branch). Finish that one first."
119}
120
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100121cmd_start() {
Vincent Driessenca73caf2010-02-07 19:46:38 +0100122 DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100123 parse_args "$@"
Vincent Driessenc5fcc012010-02-10 00:18:08 +0100124 BASE=${2:-$DEVELOP_BRANCH}
Vincent Driessen3c337fb2010-02-04 11:30:18 +0100125 require_version_arg
Vincent Driessen010252a2010-02-04 10:31:29 +0100126 require_base_is_on_develop
Vincent Driessen6d64d2c2010-02-16 06:41:13 +0100127 require_no_existing_release_branches
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100128
129 # sanity checks
Vincent Driessen7832d6e2010-02-21 21:31:03 +0100130 require_clean_working_tree
131 require_branch_absent "$BRANCH"
132 require_tag_absent "$VERSION_PREFIX$VERSION"
Vincent Driessenca73caf2010-02-07 19:46:38 +0100133 if flag fetch; then
Vincent Driessena4dd2232010-02-10 00:34:59 +0100134 git fetch -q "$ORIGIN" "$DEVELOP_BRANCH"
Vincent Driessen2acfffd2010-01-29 12:37:22 +0100135 fi
Vincent Driessen7832d6e2010-02-21 21:31:03 +0100136 require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100137
138 # create branch
Vincent Driessena4dd2232010-02-10 00:34:59 +0100139 git checkout -b "$BRANCH" "$BASE"
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100140
141 echo
142 echo "Summary of actions:"
Vincent Driessen010252a2010-02-04 10:31:29 +0100143 echo "- A new branch '$BRANCH' was created, based on '$BASE'"
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100144 echo "- You are now on branch '$BRANCH'"
145 echo
146 echo "Follow-up actions:"
147 echo "- Bump the version number now!"
148 echo "- Start committing last-minute fixes in preparing your release"
149 echo "- When done, run:"
150 echo
Vincent Driessen010252a2010-02-04 10:31:29 +0100151 echo " git flow release finish '$VERSION'"
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100152 echo
153}
154
155cmd_finish() {
Vincent Driessenca73caf2010-02-07 19:46:38 +0100156 DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
Vincent Driessen1a2868b2010-02-07 23:23:16 +0100157 DEFINE_boolean sign false "sign the release tag cryptographically" s
158 DEFINE_string signingkey "" "use the given GPG-key for the digital signature (implies -s)" u
159 DEFINE_string message "" "use the given tag message" m
Vincent Driessenddba2df2010-02-19 06:42:18 +0100160 DEFINE_boolean push false "push to $ORIGIN after performing finish" p
Jason L. Shiffer6809f0e2010-02-18 23:57:08 -0500161
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100162 parse_args "$@"
Vincent Driessen3c337fb2010-02-04 11:30:18 +0100163 require_version_arg
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100164
Vincent Driessen1a2868b2010-02-07 23:23:16 +0100165 # handle flags that imply other flags
166 if [ "$FLAGS_signingkey" != "" ]; then
167 FLAGS_sign=$FLAGS_TRUE
168 fi
169
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100170 # sanity checks
Vincent Driessen7832d6e2010-02-21 21:31:03 +0100171 require_branch "$BRANCH"
172 require_clean_working_tree
Vincent Driessenca73caf2010-02-07 19:46:38 +0100173 if flag fetch; then
Vincent Driessena4dd2232010-02-10 00:34:59 +0100174 git fetch -q "$ORIGIN" "$MASTER_BRANCH" || \
Vincent Driessen1a2868b2010-02-07 23:23:16 +0100175 die "Could not fetch $MASTER_BRANCH from $ORIGIN."
Vincent Driessena4dd2232010-02-10 00:34:59 +0100176 git fetch -q "$ORIGIN" "$DEVELOP_BRANCH" || \
Vincent Driessen1a2868b2010-02-07 23:23:16 +0100177 die "Could not fetch $DEVELOP_BRANCH from $ORIGIN."
Vincent Driessen2acfffd2010-01-29 12:37:22 +0100178 fi
Vincent Driessen7832d6e2010-02-21 21:31:03 +0100179 require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
180 require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100181
Vincent Driessen5fa47582010-02-09 00:31:33 +0100182 # try to merge into master
183 # in case a previous attempt to finish this release branch has failed,
184 # but the merge into master was successful, we skip it now
Vincent Driessen7832d6e2010-02-21 21:31:03 +0100185 if ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then
Vincent Driessena4dd2232010-02-10 00:34:59 +0100186 git checkout "$MASTER_BRANCH" || \
Vincent Driessen5fa47582010-02-09 00:31:33 +0100187 die "Could not check out $MASTER_BRANCH."
Vincent Driessena4dd2232010-02-10 00:34:59 +0100188 git merge --no-ff "$BRANCH" || \
Vincent Driessen5fa47582010-02-09 00:31:33 +0100189 die "There were merge conflicts."
190 # TODO: What do we do now?
191 fi
Vincent Driessen1a2868b2010-02-07 23:23:16 +0100192
Vincent Driessen5fa47582010-02-09 00:31:33 +0100193 # try to tag the release
194 # in case a previous attempt to finish this release branch has failed,
195 # but the tag was set successful, we skip it now
Vincent Driessenf46e2902010-02-15 23:01:52 +0100196 local tagname=$VERSION_PREFIX$VERSION
Vincent Driessen7832d6e2010-02-21 21:31:03 +0100197 if ! git_tag_exists "$tagname"; then
Vincent Driessenf46e2902010-02-15 23:01:52 +0100198 local opts="-a"
Vincent Driessen5fa47582010-02-09 00:31:33 +0100199 flag sign && opts="$opts -s"
200 [ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
201 [ "$FLAGS_message" != "" ] && opts="$opts -m '$FLAGS_message'"
202 git tag $opts "$tagname" || \
203 die "Tagging failed. Please run finish again to retry."
204 fi
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100205
Vincent Driessen5fa47582010-02-09 00:31:33 +0100206 # try to merge into develop
207 # in case a previous attempt to finish this release branch has failed,
208 # but the merge into develop was successful, we skip it now
Vincent Driessen7832d6e2010-02-21 21:31:03 +0100209 if ! git_is_branch_merged_into "$BRANCH" "$DEVELOP_BRANCH"; then
Vincent Driessena4dd2232010-02-10 00:34:59 +0100210 git checkout "$DEVELOP_BRANCH" || \
Vincent Driessen5fa47582010-02-09 00:31:33 +0100211 die "Could not check out $DEVELOP_BRANCH."
Vincent Driessend29e3152010-02-09 00:55:06 +0100212
213 # TODO: Actually, accounting for 'git describe' pays, so we should
214 # ideally git merge --no-ff $tagname here, instead!
Vincent Driessena4dd2232010-02-10 00:34:59 +0100215 git merge --no-ff "$BRANCH" || \
Vincent Driessen5fa47582010-02-09 00:31:33 +0100216 die "There were merge conflicts."
217 # TODO: What do we do now?
218 fi
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100219
220 # delete branch
Vincent Driessena4dd2232010-02-10 00:34:59 +0100221 git branch -d "$BRANCH"
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100222
Vincent Driessenddba2df2010-02-19 06:42:18 +0100223 if flag push; then
224 git push "$ORIGIN" "$DEVELOP_BRANCH" || \
225 die "Could not push to $DEVELOP_BRANCH from $ORIGIN."
226 git push "$ORIGIN" "$MASTER_BRANCH" || \
227 die "Could not push to $MASTER_BRANCH from $ORIGIN."
228 git push --tags "$ORIGIN" || \
229 die "Could not push tags to $ORIGIN."
230 fi
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100231
232 echo
233 echo "Summary of actions:"
Benedikt Böhm350e7152010-01-26 13:05:05 +0100234 echo "- Latest objects have been fetched from '$ORIGIN'"
Benedikt Böhm4a864fb2010-01-26 12:59:27 +0100235 echo "- Release branch has been merged into '$MASTER_BRANCH'"
Vincent Driessen5fa47582010-02-09 00:31:33 +0100236 echo "- The release was tagged '$tagname'"
Benedikt Böhm4a864fb2010-01-26 12:59:27 +0100237 echo "- Release branch has been back-merged into '$DEVELOP_BRANCH'"
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100238 echo "- Release branch '$BRANCH' has been deleted"
Vincent Driessenddba2df2010-02-19 06:42:18 +0100239 if flag push; then
240 echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'"
241 fi
Benedikt Böhm00ccea62010-01-26 12:39:36 +0100242 echo
243}