1# $Id$
2# vim:et:ft=sh:sts=2:sw=2
3#
4# git-flow -- A collection of Git extensions to provide high-level
5# repository operations for Vincent Driessen's branching model.
6#
7# A blog post presenting this model is found at:
8#    http://blog.avirtualhome.com/development-workflow-using-git/
9#
10# Feel free to contribute to this project at:
11#    http://github.com/petervanderdoes/gitflow
12#
13# Authors:
14# Copyright 2012-2019 Peter van der Does. All rights reserved.
15#
16# Original Author:
17# Copyright 2010 Vincent Driessen. All rights reserved.
18#
19# Redistribution and use in source and binary forms, with or without
20# modification, are permitted provided that the following conditions are met:
21#
22# 1. Redistributions of source code must retain the above copyright notice, this
23#    list of conditions and the following disclaimer.
24# 2. Redistributions in binary form must reproduce the above copyright notice,
25#    this list of conditions and the following disclaimer in the documentation
26#    and/or other materials provided with the distribution.
27#
28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
29# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
32# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38#
39
40#
41# Function used by finish command to actually finish the release branch
42# Called when the base of the release is the $DEVELOP_BRANCH
43#
44_finish_from_develop() {
45	local opts merge_branch commit keepmsg remotebranchdeleted localbranchdeleted compare_refs_result merge_result
46
47	remotebranchdeleted=$FLAGS_FALSE
48	localbranchdeleted=$FLAGS_FALSE
49
50	# Update local branches with remote branches
51	if flag fetch; then
52		git_fetch_branch "$ORIGIN" "$MASTER_BRANCH"
53		git_fetch_branch "$ORIGIN" "$DEVELOP_BRANCH"
54	fi
55
56	# Check if the local branches have all the commits from the remote branches
57	if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
58		require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH"
59	fi
60	if git_remote_branch_exists "$ORIGIN/$MASTER_BRANCH"; then
61		if flag ff_master; then
62			git_compare_refs "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
63			compare_refs_result=$?
64
65			if [ $compare_refs_result -gt 0 ]; then
66				warn "Branches '"$MASTER_BRANCH"' and '"$ORIGIN/$MASTER_BRANCH"' have diverged."
67				if [ $compare_refs_result -eq 1 ]; then
68					warn "Fast forwarding '"$MASTER_BRANCH"'."
69					git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
70					git_do merge  --ff-only "$ORIGIN/$MASTER_BRANCH" >/dev/null 2>&1
71					merge_result=$?
72					git_do checkout "$BRANCH"
73					if [ $merge_result -gt 0 ]; then
74						die "'"$MASTER_BRANCH"' can not be fast forwarded."
75					fi
76				elif [ $compare_refs_result -eq 2 ]; then
77					# Warn here, since there is no harm in being ahead
78					warn "And local branch '$1' is ahead of '$2'."
79				else
80					die "Branches need merging first."
81				fi
82			fi
83		else
84			require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
85		fi
86	fi
87	if git_remote_branch_exists "$ORIGIN/$DEVELOP_BRANCH"; then
88		require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
89	fi
90
91	if noflag notag; then
92		# We ask for a tag, be sure it does not exists or
93		# points to the latest hotfix commit
94		if git_tag_exists "$VERSION_PREFIX$TAGNAME"; then
95			git_compare_refs  "$BRANCH" "$VERSION_PREFIX$TAGNAME"^2 2>/dev/null
96			[ $? -eq 0 ] || die "Tag already exists and does not point to release branch '$BRANCH'"
97		fi
98	fi
99
100	run_pre_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
101
102	# Try to merge into master.
103	# In case a previous attempt to finish this release branch has failed,
104	# but the merge into master was successful, we skip it now
105	if ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then
106			git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
107			if noflag squash; then
108				git_do merge --no-ff "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now?
109			else
110				git_do merge --squash "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now?
111				flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$MASTER_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG"
112				git_do commit
113			fi
114	fi
115
116	if noflag notag; then
117		# Try to tag the release.
118		# In case a previous attempt to finish this release branch has failed,
119		# but the tag was set successful, we skip it now
120		if ! git_tag_exists "$VERSION_PREFIX$TAGNAME"; then
121			git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
122			if [ "$FLAGS_message" != "" ] && [ "$FLAGS_messagefile" != "" ]; then
123				die "Use either -m,--message or -f,--messagefile. Can not use both options at the same time"
124			fi
125			opts="-a"
126			flag sign && opts="$opts -s"
127			[ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
128			if [ "$FLAGS_message" != "" ]; then
129				# Run filter on the tag message
130				FLAGS_message=$(run_filter_hook release-finish-tag-message "${FLAGS_message}" "$VERSION_PREFIX$TAGNAME")
131				opts="$opts -m '$FLAGS_message'"
132			fi
133			[ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'"
134			eval git_do tag $opts "$VERSION_PREFIX$TAGNAME" || die "Tagging failed. Please run finish again to retry."
135		fi
136	fi
137
138	# By default we backmerge the $MASTER_BRANCH unless the user explicitly
139	# stated not to do a back merge, in that case we use the $BRANCH.
140	if noflag nobackmerge; then
141		merge_branch="$MASTER_BRANCH"
142	else
143		merge_branch="$BRANCH"
144	fi
145
146	# Try to merge into develop unless 'nodevelopmerge' has been specified.
147	# In case a previous attempt to finish this release branch has failed,
148	# but the merge into develop was successful, we skip it now
149	if noflag nodevelopmerge; then
150		if ! git_is_branch_merged_into "$merge_branch" "$DEVELOP_BRANCH"; then
151			git_do checkout "$DEVELOP_BRANCH" || die "Could not check out branch '$DEVELOP_BRANCH'."
152
153			if noflag nobackmerge; then
154				# Accounting for 'git describe', if a release is tagged
155				# we use the tag commit instead of the branch.
156				if noflag notag; then
157					commit="$VERSION_PREFIX$TAGNAME"
158				else
159					commit="$MASTER_BRANCH"
160				fi
161				git_do merge --no-ff "$commit" || die "There were merge conflicts." # TODO: What do we do now?
162			else
163				commit="$BRANCH"
164				if noflag squash; then
165					git_do merge --no-ff "$commit" || die "There were merge conflicts." # TODO: What do we do now?
166				else
167					git_do merge --squash "$commit" || die "There were merge conflicts." # TODO: What do we do now?
168					flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$DEVELOP_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG"
169					git_do commit
170				fi
171			fi
172		fi
173	fi
174
175	run_post_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
176
177	if flag push; then
178		if flag pushdevelop; then
179			git_do push "$ORIGIN" "$DEVELOP_BRANCH" || die "Could not push branch '$DEVELOP_BRANCH' to remote '$ORIGIN'."
180		fi
181		if flag pushproduction; then
182			git_do push "$ORIGIN" "$MASTER_BRANCH" || die "Could not push branch '$MASTER_BRANCH' to remote '$ORIGIN'."
183		fi
184		if noflag notag && flag pushtag; then
185			git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'."
186		fi
187	fi
188
189	# Delete branch
190	if noflag keep; then
191
192		if [ "$BRANCH" = "$(git_current_branch)" ]; then
193			git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
194		fi
195
196		# Always delete remote first
197		if noflag keepremote;then
198			if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
199				git_remote_branch_delete "$BRANCH" && remotebranchdeleted=$FLAGS_TRUE
200			fi
201		fi
202
203		# Delete local after remote to avoid warnings
204		if noflag keeplocal; then
205			if flag force_delete; then
206				git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
207			else
208				if noflag squash; then
209					git_do branch -d "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
210				else
211					git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
212				fi
213			fi
214		fi
215
216		# no more branches: we can safely remove config section
217		if ! git_remote_branch_exists "$ORIGIN/$BRANCH" -a ! git_local_branch_exists "$BRANCH"; then
218			gitflow_config_remove_base_section "$BRANCH"
219		fi
220	fi
221
222	echo
223	echo "Summary of actions:"
224	if flag fetch; then
225		echo "- Latest objects have been fetched from '$ORIGIN'"
226	fi
227	echo "- Release branch '$BRANCH' has been merged into '$MASTER_BRANCH'"
228	if noflag notag; then
229		echo "- The release was tagged '$VERSION_PREFIX$TAGNAME'"
230	fi
231	[ "$commit" = "$MASTER_BRANCH" ] && echo "- Master branch '$MASTER_BRANCH' has been back-merged into '$DEVELOP_BRANCH'"
232	[ "$commit" = "$VERSION_PREFIX$TAGNAME" ] && echo "- Release tag '$VERSION_PREFIX$TAGNAME' has been back-merged into '$DEVELOP_BRANCH'"
233	[ "$commit" = "$BRANCH" ] && echo "- Release branch '$BRANCH' has been merged into '$DEVELOP_BRANCH'"
234
235	if noflag keep; then
236		if [ $localbranchdeleted -eq $FLAGS_TRUE ]; then
237			keepmsg="has been locally deleted"
238		else
239			keepmsg="is still locally available"
240		fi
241		if [ $remotebranchdeleted -eq $FLAGS_TRUE ]; then
242			keepmsg=$keepmsg"; it has been remotely deleted from '$ORIGIN'"
243		elif git_remote_branch_exists "$ORIGIN/$BRANCH"; then
244			keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'"
245		fi
246	else
247		keepmsg="is still locally available"
248		if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
249			keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'"
250		fi
251	fi
252	echo "- Release branch '$BRANCH' "$keepmsg
253
254	if flag push; then
255		echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'"
256	fi
257	echo "- You are now on branch '$(git_current_branch)'"
258	echo
259}
260
261#
262# Function used by finish command to actually finish the release branch
263# Called when the base of the release is NOT the $DEVELOP_BRANCH
264#
265
266_finish_base() {
267	local opts merge_branch commit keepmsg localbranchdeleted remotebranchdeleted
268
269	remotebranchdeleted=$FLAGS_FALSE
270	localbranchdeleted=$FLAGS_FALSE
271
272	# Update local branches with remote branches
273	if flag fetch; then
274		git_fetch_branch "$ORIGIN" "$BASE_BRANCH"
275	fi
276
277	# Check if the local branches have all the commits from the remote branches
278	if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
279		require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH"
280	fi
281	if git_remote_branch_exists "$ORIGIN/$BASE_BRANCH"; then
282		require_branches_equal "$BASE_BRANCH" "$ORIGIN/$BASE_BRANCH"
283	fi
284
285	if noflag notag; then
286		# We ask for a tag, be sure it does not exists or
287		# points to the latest hotfix commit
288		if git_tag_exists "$VERSION_PREFIX$TAGNAME"; then
289			git_compare_refs  "$BRANCH" "$VERSION_PREFIX$TAGNAME"^2 2>/dev/null
290			[ $? -eq 0 ] || die "Tag already exists and does not point to release branch '$BRANCH'"
291		fi
292	fi
293
294	run_pre_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
295
296	# Try to merge into base branch.
297	# In case a previous attempt to finish this release branch has failed,
298	# but the merge into develop was successful, we skip it now
299	if ! git_is_branch_merged_into "$BRANCH" "$BASE_BRANCH"; then
300		git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'."
301		if noflag squash; then
302			git_do merge --no-ff "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now?
303		else
304			git_do merge --squash "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now?
305			flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$BASE_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG"
306			git_do commit
307		fi
308	fi
309
310	if noflag notag; then
311		# Try to tag the release.
312		# In case a previous attempt to finish this release branch has failed,
313		# but the tag was set successful, we skip it now
314		if ! git_tag_exists "$VERSION_PREFIX$TAGNAME"; then
315			git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'."
316			if [ "$FLAGS_message" != "" ] && [ "$FLAGS_messagefile" != "" ]; then
317				die "Use either -m,--message or -f,--messagefile. Can not use both options at the same time"
318			fi
319			opts="-a"
320			flag sign && opts="$opts -s"
321			[ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
322			if [ "$FLAGS_message" != "" ]; then
323				# Run filter on the tag message
324				FLAGS_message=$(run_filter_hook release-finish-tag-message "${FLAGS_message}" "$VERSION_PREFIX$TAGNAME")
325				opts="$opts -m '$FLAGS_message'"
326			fi
327			[ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'"
328			eval git_do tag $opts "$VERSION_PREFIX$TAGNAME" || die "Tagging failed. Please run finish again to retry."
329		fi
330	fi
331
332	run_post_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
333
334	# Delete branch
335	if noflag keep; then
336
337		# Always delete remote first
338		if noflag keepremote;then
339			if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
340				git_remote_branch_delete "$BRANCH" && remotebranchdeleted=$FLAGS_TRUE
341			fi
342		fi
343
344		# Delete local after remote to avoid warnings
345		if noflag keeplocal; then
346			if [ "$BRANCH" = "$(git_current_branch)" ]; then
347				git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'."
348			fi
349			if flag force_delete; then
350				git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
351			else
352				git_do branch -d "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
353			fi
354		fi
355
356		# no more branches: we can safely remove config section
357		if ! git_remote_branch_exists "$ORIGIN/$BRANCH" -a ! git_local_branch_exists "$BRANCH"; then
358			gitflow_config_remove_base_section "$BRANCH"
359		fi
360	fi
361
362	if flag push; then
363		if flag pushdevelop; then
364			git_do push "$ORIGIN" "$BASE_BRANCH" || die "Could not push branch '$BASE_BRANCH' to remote '$ORIGIN'."
365		fi
366		if noflag notag && flag pushtag; then
367			git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'."
368		fi
369	fi
370
371	echo
372	echo "Summary of actions:"
373	if flag fetch; then
374		echo "- Latest objects have been fetched from '$ORIGIN'"
375	fi
376	if noflag notag; then
377		echo "- The release was tagged '$VERSION_PREFIX$TAGNAME'"
378	fi
379	[ "$commit" = "$VERSION_PREFIX$TAGNAME" ] && echo "- Release tag '$VERSION_PREFIX$TAGNAME' has been merged into '$BASE_BRANCH'"
380	[ "$commit" = "$BRANCH" ] && echo "- Release branch '$BRANCH' has been merged into '$BASE_BRANCH'"
381	if noflag keep; then
382		if [ $localbranchdeleted -eq $FLAGS_TRUE ]; then
383			keepmsg="has been locally deleted"
384		else
385			keepmsg="is still locally available"
386		fi
387		if [ $remotebranchdeleted -eq $FLAGS_TRUE ]; then
388			keepmsg=$keepmsg"; it has been remotely deleted from '$ORIGIN'"
389		elif git_remote_branch_exists "$ORIGIN/$BRANCH"; then
390			keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'"
391		fi
392	else
393		keepmsg="is still locally available"
394		if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
395			keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'"
396		fi
397	fi
398	echo "- Release branch '$BRANCH' "$keepmsg
399
400	if flag push; then
401		echo "- '$BASE_BRANCH' and tags have been pushed to '$ORIGIN'"
402	fi
403	echo "- You are now on branch '$(git_current_branch)'"
404	echo
405}
406initialize() {
407	require_git_repo
408	require_gitflow_initialized
409	git config --get gitflow.prefix.release >/dev/null 2>&1 || die "Release prefix not set. Please run 'git flow init'."
410	gitflow_load_settings
411	VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
412	PREFIX=$(git config --get gitflow.prefix.release)
413}
414
415usage() {
416		OPTIONS_SPEC="\
417git flow release [list]
418git flow release start
419git flow release finish
420git flow release publish
421git flow release track
422git flow release delete
423
424Manage your release branches.
425
426For more specific help type the command followed by --help
427--
428"
429	flags_help
430}
431
432cmd_default() {
433	cmd_list "$@"
434}
435
436cmd_list() {
437		OPTIONS_SPEC="\
438git flow release [list] [-h] [-v]
439
440List existing release branches
441--
442h,help!           Show this help
443v,verbose!        verbose (more) output
444"
445	local release_branches current_branch
446	local width branch len
447	local base develop_sha branch_sha nicename
448
449	# cmd_default may already define flags
450	# at this stage we can not use parse_args
451	if [ -z "${FLAGS_verbose}" ]; then
452		DEFINE_boolean 'verbose' false 'verbose (more) output' v
453	fi
454
455	# Parse arguments
456	parse_args "$@"
457
458	release_branches=$(git_local_branches_prefixed "$PREFIX")
459	if [ -z "$release_branches" ]; then
460		warn "No release branches exist."
461		warn ""
462		warn "You can start a new release branch:"
463		warn ""
464		warn "    git flow release start <name> [<base>]"
465		warn ""
466		exit 0
467	fi
468
469	current_branch=$(git_current_branch)
470
471	# Determine column width first
472	width=0
473	for branch in $release_branches; do
474		len=${#branch}
475		width=$(max $width $len)
476	done
477	width=$(($width+3-${#PREFIX}))
478
479	for branch in $release_branches; do
480		base=$(git merge-base "$branch" "$DEVELOP_BRANCH")
481		develop_sha=$(git rev-parse "$DEVELOP_BRANCH")
482		branch_sha=$(git rev-parse "$branch")
483		if [ "$branch" = "$current_branch" ]; then
484			printf "* "
485		else
486			printf "  "
487		fi
488		if flag verbose; then
489			printf "%-${width}s" "${branch#$PREFIX}"
490			if [ "$branch_sha" = "$develop_sha" ]; then
491				printf "(no commits yet)"
492			else
493				nicename=$(git rev-parse --short "$base")
494				printf "(based on $nicename)"
495			fi
496		else
497			printf "%s" "${branch#$PREFIX}"
498		fi
499		echo
500	done
501}
502
503cmd_help() {
504	usage
505	exit 0
506}
507
508# Parse arguments and set common variables
509parse_args() {
510	FLAGS "$@" || exit $?
511	eval set -- "${FLAGS_ARGV}"
512
513	# Read arguments into global variables
514	if [ -z $1 ]; then
515		VERSION=''
516	else
517		VERSION=$1
518	fi
519	BRANCH=$PREFIX$VERSION
520}
521
522require_no_existing_release_branches() {
523	local release_branches first_branch
524
525	release_branches=$(git_local_branches_prefixed "$PREFIX")
526	first_branch=$(echo ${release_branches} | head -n1)
527
528	first_branch=${first_branch#$PREFIX}
529	[ -z "$release_branches" ] || die "There is an existing release branch '$first_branch'. Finish that one first."
530}
531
532cmd_start() {
533	OPTIONS_SPEC="\
534git flow release start [options] <version> [<base>]
535
536Start a new release branch
537--
538h,help!              Show this help
539showcommands!        Show git commands while executing them
540F,[no]fetch          Fetch from $ORIGIN before performing finish
541v,verbose!           Verbose (more) output
542"
543	local base
544
545	# Define flags
546	DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F
547
548	# Override defaults with values from config
549	gitflow_override_flag_boolean   "release.start.fetch"   "fetch"
550
551	# Parse arguments
552	parse_args "$@"
553	eval set -- "${FLAGS_ARGV}"
554	base=${2:-$DEVELOP_BRANCH}
555
556	# Run filter on the version
557	VERSION=$(run_filter_hook release-start-version $VERSION)
558	if [ $? -eq 127 ]; then
559		die $VERSION
560	fi
561
562	# As VERSION might have changed reset BRANCH with new VERSION
563	BRANCH=$PREFIX$VERSION
564
565	require_base_is_local_branch "$base"
566	gitflow_require_version_arg
567
568	require_no_existing_release_branches
569
570	# Sanity checks
571	git_config_bool_exists "gitflow.allowdirty" || require_clean_working_tree
572	require_branch_absent "$BRANCH"
573	require_tag_absent "$VERSION_PREFIX$VERSION"
574	if flag fetch; then
575		git_fetch_branch "$ORIGIN" "$base"
576	fi
577	if git_remote_branch_exists "$ORIGIN/$base"; then
578		require_branches_equal "$base" "$ORIGIN/$base"
579	fi
580
581	run_pre_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH" "$base"
582
583	gitflow_config_set_base_branch $base $BRANCH
584
585	# Create branch
586	git_do checkout -b "$BRANCH" "$base" || die "Could not create release branch '$BRANCH'."
587
588	run_post_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH" "$base"
589
590	echo
591	echo "Summary of actions:"
592	echo "- A new branch '$BRANCH' was created, based on '$base'"
593	echo "- You are now on branch '$(git_current_branch)'"
594	echo
595	echo "Follow-up actions:"
596	echo "- Bump the version number now!"
597	echo "- Start committing last-minute fixes in preparing your release"
598	echo "- When done, run:"
599	echo
600	echo "     git flow release finish '$VERSION'"
601	echo
602}
603
604cmd_finish() {
605	OPTIONS_SPEC="\
606git flow release finish [-h] [-F] [-s] [-u] [-m | -f] [-p] [-k] [-n] [-b] [-S] <version>
607
608
609Finish a release branch
610--
611h,help              Show this help
612showcommands!       Show git commands while executing them
613F,[no]fetch         Fetch from origin before performing finish
614s,sign!             Sign the release tag cryptographically
615u,signingkey!       Use the given GPG-key for the digital signature (implies -s)
616m,message!          Use the given tag message
617f,[no]messagefile=  Use the contents of the given file as a tag message
618p,[no]push          Push to origin after performing finish
619[no]pushproduction  Push the production branch
620[no]pushdevelop     Push the develop branch
621[no]pushtag         Push the tag
622k,[no]keep          Keep branch after performing finish
623[no]keepremote      Keep the remote branch
624[no]keeplocal       Keep the local branch
625D,[no]force_delete  Force delete release branch after finish
626n,[no]tag           Don't tag this release
627b,[no]nobackmerge   Don't back-merge master, or tag if applicable, in develop
628S,[no]squash        Squash release during merge
629[no]ff-master       Fast forward master branch if possible
630T,tagname!          Use given tag name
631nodevelopmerge!  Don't back-merge develop branch
632"
633	# Define flags
634	DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F
635	DEFINE_boolean 'sign' false "sign the release tag cryptographically" s
636	DEFINE_string  'signingkey' "" "use the given GPG-key for the digital signature (implies -s)" u
637	DEFINE_string  'message' "" "use the given tag message" m
638	DEFINE_string  'messagefile' "" "use the contents of the given file as a tag message" f
639	DEFINE_boolean 'push' false "push to $ORIGIN after performing finish" p
640	DEFINE_boolean 'pushproduction' false "push the production branch"
641	DEFINE_boolean 'pushdevelop' false "push the develop branch"
642	DEFINE_boolean 'pushtag' false "push the tag"
643	DEFINE_boolean 'keep' false "keep branch after performing finish" k
644	DEFINE_boolean 'keepremote' false "keep the remote branch"
645	DEFINE_boolean 'keeplocal' false "keep the local branch"
646	DEFINE_boolean 'force_delete' false "force delete release branch after finish" D
647	DEFINE_boolean 'notag' false "don't tag this release" n
648	DEFINE_boolean 'nobackmerge' false "don't back-merge $MASTER_BRANCH, or tag if applicable, in $DEVELOP_BRANCH " b
649	DEFINE_boolean 'squash' false "squash release during merge" S
650	DEFINE_boolean 'squash-info' false "add branch info during squash"
651	DEFINE_boolean 'ff-master' false "fast forward master branch if possible"
652	DEFINE_string  'tagname' "" "use the given tag name" T
653	DEFINE_boolean 'nodevelopmerge' false "don't merge $BRANCH into $DEVELOP_BRANCH "
654
655	# Override defaults with values from config
656	gitflow_override_flag_boolean   "release.finish.fetch"          "fetch"
657	gitflow_override_flag_boolean   "release.finish.sign"           "sign"
658	gitflow_override_flag_boolean   "release.finish.push"           "push"
659	gitflow_override_flag_boolean   "release.finish.pushproduction" "pushproduction"
660	gitflow_override_flag_boolean   "release.finish.pushdevelop"    "pushdevelop"
661	gitflow_override_flag_boolean   "release.finish.pushtag"        "pushtag"
662	gitflow_override_flag_boolean   "release.finish.keep"           "keep"
663	gitflow_override_flag_boolean   "release.finish.keepremote"     "keepremote"
664	gitflow_override_flag_boolean   "release.finish.keeplocal"      "keeplocal"
665	gitflow_override_flag_boolean   "release.finish.force-delete"   "force_delete"
666	gitflow_override_flag_boolean   "release.finish.notag"          "notag"
667	gitflow_override_flag_boolean   "release.finish.nobackmerge"    "nobackmerge"
668	gitflow_override_flag_boolean   "release.finish.squash"         "squash"
669	gitflow_override_flag_boolean   "release.finish.squash-info"    "squash_info"
670	gitflow_override_flag_boolean   "release.finish.ff-master"      "ff-master"
671	gitflow_override_flag_string    "release.finish.signingkey"     "signingkey"
672	gitflow_override_flag_string    "release.finish.message"        "message"
673	gitflow_override_flag_string    "release.finish.messagefile"    "messagefile"
674	gitflow_override_flag_boolean   "release.finish.nodevelopmerge" "nodevelopmerge"
675
676	# Parse arguments
677	parse_args "$@"
678
679	# Use current branch if no version is given
680	if [ "$VERSION" = "" ]; then
681		gitflow_use_current_branch_version
682	fi
683
684
685	# Run filter on the version
686	VERSION=$(run_filter_hook release-finish-version $VERSION)
687	if [ $? -eq 127 ]; then
688		die $VERSION
689	fi
690
691	# Use branch name if no tag name is given
692	if [ "$FLAGS_tagname" != "" ]; then
693		TAGNAME=$FLAGS_tagname
694	else
695		TAGNAME=$VERSION
696	fi
697
698	# As VERSION might have changed reset BRANCH with new VERSION
699	BRANCH=$PREFIX$VERSION
700
701	BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
702	BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH}
703	git_local_branch_exists "$BASE_BRANCH" || die "The base '$BASE_BRANCH' doesn't exists locally or is not a branch. Can't finish the release branch '$BRANCH'."
704
705	# Handle flags that imply other flags
706	if [ "$FLAGS_signingkey" != "" ]; then
707		FLAGS_sign=$FLAGS_TRUE
708	fi
709
710	# Keeping both branches implies the --keep flag to be true.
711	if flag keepremote && flag keeplocal; then
712		FLAGS_keep=$FLAGS_TRUE
713	fi
714
715	# Pushing implies we push all.
716	if flag push; then
717		FLAGS_pushproduction=$FLAGS_TRUE
718		FLAGS_pushdevelop=$FLAGS_TRUE
719		FLAGS_pushtag=$FLAGS_TRUE
720	fi
721	# If we push either of these it means we need to do a push
722	if flag pushproduction || flag pushdevelop || flag pushtag; then
723		FLAGS_push=$FLAGS_TRUE
724	fi
725
726	# Sanity checks
727	require_branch "$BRANCH"
728	require_clean_working_tree
729
730	# We always fetch the Branch from Origin
731	# This is done to avoid possible commits on the remote that are not
732	# merged into the local branch
733	if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
734			git_fetch_branch "$ORIGIN" "$BRANCH"
735	fi
736
737	if [ "$BASE_BRANCH" = "$DEVELOP_BRANCH" ]; then
738		_finish_from_develop
739	else
740		_finish_base
741	fi
742}
743
744cmd_branch() {
745	OPTIONS_SPEC="\
746git flow release branch [-h] [-F] [-s] [-u] [-m] [-f] [-p] [-n] [-S] <version> [<name>]
747
748
749Release a branch [<name>], if a name is not given it defaults to the develop branch, and use the given version <version>
750--
751h,help              Show this help
752showcommands!       Show git commands while executing them
753F,[no]fetch 		Fetch from origin before performing finish
754s,sign!             Sign the release tag cryptographically
755u,signingkey!    	Use the given GPG-key for the digital signature (implies -s)
756m,message! 	    	Use the given tag message
757f,[no]messagefile= 	Use the contents of the given file as a tag message
758p,[no]push 			Push to origin after performing finish
759n,[no]tag 			Don't tag this release
760S,[no]squash 		Squash release during merge
761"
762	local opts
763
764	# Define flags
765	DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F
766	DEFINE_boolean 'sign' false "sign the release tag cryptographically" s
767	DEFINE_string 'signingkey' "" "use the given GPG-key for the digital signature (implies -s)" u
768	DEFINE_string 'message' "" "use the given tag message" m
769	DEFINE_string 'messagefile' "" "use the contents of the given file as a tag message" f
770	DEFINE_boolean 'push' false "push to $ORIGIN after performing finish" p
771	DEFINE_boolean 'notag' false "don't tag this release" n
772	DEFINE_boolean 'squash' false "squash release during merge" S
773	DEFINE_boolean 'squash-info' false "add branch info during squash"
774
775	# Override defaults with values from config
776	gitflow_override_flag_boolean   "release.branch.fetch"         "fetch"
777	gitflow_override_flag_boolean   "release.branch.sign"          "sign"
778	gitflow_override_flag_boolean   "release.branch.push"          "push"
779	gitflow_override_flag_boolean   "release.branch.notag"         "notag"
780	gitflow_override_flag_boolean   "release.branch.squash"        "squash"
781	gitflow_override_flag_boolean   "release.branch.squash-info"   "squash_info"
782	gitflow_override_flag_string    "release.branch.signingkey"    "signingkey"
783	gitflow_override_flag_string    "release.branch.message"       "message"
784	gitflow_override_flag_string    "release.branch.messagefile"   "messagefile"
785
786	# Parse arguments
787	FLAGS "$@" || exit $?
788	eval set -- "${FLAGS_ARGV}"
789
790	# Read arguments into global variables
791	VERSION=$1
792	BRANCH=${2:-$DEVELOP_BRANCH}
793
794	# Run filter on the version
795	VERSION=$(run_filter_hook branch-finish-version $VERSION)
796	if [ $? -eq 127 ]; then
797		die $VERSION
798	fi
799
800	gitflow_require_version_arg
801
802	# Handle flags that imply other flags
803	if [ "$FLAGS_signingkey" != "" ]; then
804		FLAGS_sign=$FLAGS_TRUE
805	fi
806
807	# Sanity checks
808	if gitflow_is_prefixed_branch "$BRANCH"; then
809		die "Branch '$BRANCH' seems to be a git-flow branch. It's not allowed to release this directly."
810	fi
811
812	if [ "$BRANCH" = "$MASTER_BRANCH" ]; then
813		die "Can not release from the the master branch"
814	fi
815
816	require_branch "$BRANCH"
817	require_clean_working_tree
818
819	# We always fetch the Branch from Origin
820	# This is done to avoid possible commits on the remote that are not
821	# merged into the local branch
822	if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
823			git_fetch_branch "$ORIGIN" "$BRANCH"
824	fi
825
826	# Update local branches with remote branches
827	if flag fetch; then
828		git_fetch_branch "$ORIGIN" "$MASTER_BRANCH"
829	fi
830
831	# Check if the local branches have all the commits from the remote branches
832	if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
833		require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH"
834	fi
835	if git_remote_branch_exists "$ORIGIN/$MASTER_BRANCH"; then
836		require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
837	fi
838
839	run_pre_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH"
840
841	# Try to merge into master.
842	# In case a previous attempt to finish this release branch has failed,
843	# but the merge into master was successful, we skip it now
844	if ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then
845			git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
846			if noflag squash; then
847				git_do merge --no-ff "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now?
848			else
849				git_do merge --squash "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now?
850				flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$MASTER_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG"
851				git_do commit
852			fi
853	fi
854
855	if noflag notag; then
856		# Try to tag the release.
857		# In case a previous attempt to finish this release branch has failed,
858		# but the tag was set successful, we skip it now
859		if ! git_tag_exists "$VERSION_PREFIX$VERSION"; then
860			if [ "$FLAGS_message" != "" ] && [ "$FLAGS_messagefile" != "" ]; then
861				die "Use either -m,--message or -f,--messagefile. Can not use both options at the same time"
862			fi
863			opts="-a"
864			flag sign && opts="$opts -s"
865			[ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
866			if [ "$FLAGS_message" != "" ]; then
867				# Run filter on the tag message
868				FLAGS_message=$(run_filter_hook release-branch-tag-message "${FLAGS_message}" "$VERSION_PREFIX$VERSION")
869				opts="$opts -m '$FLAGS_message'"
870			fi
871			[ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'"
872			eval git_do tag $opts "$VERSION_PREFIX$VERSION" || die "Tagging failed. Please run finish again to retry."
873		fi
874	fi
875
876	run_post_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH"
877
878	if flag push; then
879		git_do push "$ORIGIN" "$MASTER_BRANCH" || die "Could not push branch '$MASTER_BRANCH' to remote '$ORIGIN'."
880		if noflag notag; then
881			git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'."
882		fi
883	fi
884
885	echo
886	echo "Summary of actions:"
887	if flag fetch; then
888		echo "- Latest objects have been fetched from '$ORIGIN'"
889	fi
890	echo "- Branch '$BRANCH' has been merged into '$MASTER_BRANCH'"
891	if noflag notag; then
892		echo "- The release was tagged '$VERSION_PREFIX$VERSION'"
893	fi
894
895	if flag push; then
896		echo "- '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'"
897	fi
898	echo "- You are now on branch '$(git_current_branch)'"
899	echo
900}
901
902cmd_publish() {
903	OPTIONS_SPEC="\
904git flow release publish [-h] <name>
905
906Publish the release branch <name> on $ORIGIN
907--
908h,help           Show this help
909showcommands!    Show git commands while executing them
910"
911	# Parse arguments
912	parse_args "$@"
913
914	# Use current branch if no version is given
915	if [ "$VERSION" = "" ]; then
916		gitflow_use_current_branch_version
917	fi
918
919	# Sanity checks
920	require_clean_working_tree
921	require_branch "$BRANCH"
922	git_do fetch -q "$ORIGIN" || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'."
923	require_branch_absent "$ORIGIN/$BRANCH"
924
925	run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH"
926
927	# Create remote branch with remote tracking
928	git_do push -u "$ORIGIN" "$BRANCH:$BRANCH"
929	git_do fetch -q "$ORIGIN" "$BRANCH" || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'."
930	git_do checkout "$BRANCH" || die "Could not check out branch '$BRANCH'."
931
932	run_post_hook "$VERSION" "$ORIGIN" "$BRANCH"
933
934	echo
935	echo "Summary of actions:"
936	echo "- The remote branch '$BRANCH' was created or updated"
937	echo "- The local branch '$BRANCH' was configured to track the remote branch"
938	echo "- You are now on branch '$(git_current_branch)'"
939	echo
940}
941
942cmd_track() {
943	OPTIONS_SPEC="\
944git flow release track [-h] <name>
945
946Start tracking release <name> that is shared on $ORIGIN
947--
948h,help           Show this help
949showcommands!    Show git commands while executing them
950"
951	# Parse arguments
952	parse_args "$@"
953
954	gitflow_require_version_arg
955
956	# Sanity checks
957	require_clean_working_tree
958	require_local_branch_absent "$BRANCH"
959
960	run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH"
961
962	git_do fetch -q "$ORIGIN"  || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'."
963	git_remote_branch_exists "$ORIGIN/$BRANCH"
964
965	# Create tracking branch
966	git_do checkout -b "$BRANCH" "$ORIGIN/$BRANCH" || die "Could not create branch '$BRANCH'."
967
968	run_post_hook "$VERSION" "$ORIGIN" "$BRANCH"
969
970	echo
971	echo "Summary of actions:"
972	echo "- A new remote tracking branch '$BRANCH' was created"
973	echo "- You are now on branch '$(git_current_branch)'"
974	echo
975}
976
977cmd_rebase() {
978	OPTIONS_SPEC="\
979git flow release rebase [-h] [-i] [-p] [<name|nameprefix>]
980
981Rebase <name> on <base_branch>
982--
983h,help!                Show this help
984showcommands!          Show git commands while executing them
985i,[no]interactive      Do an interactive rebase
986p,[no]preserve-merges  Preserve merges
987"
988	local opts
989
990	# Define flags
991	DEFINE_boolean 'interactive' false 'do an interactive rebase' i
992	DEFINE_boolean 'preserve-merges' false 'try to recreate merges' p
993
994	# Override defaults with values from config
995	gitflow_override_flag_boolean   "release.rebase.interactive"       "interactive"
996	gitflow_override_flag_boolean   "release.rebase.preserve-merges"   "preserve_merges"
997
998	# Parse arguments
999	parse_args "$@"
1000
1001	# Use current branch if no version is given
1002	if [ "$VERSION" = "" ]; then
1003		gitflow_use_current_branch_version
1004	fi
1005
1006	BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
1007	BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH}
1008
1009	warn "Will try to rebase '$NAME' which is based on '$BASE_BRANCH'..."
1010	if ! git_config_bool_exists "rebase.autostash"; then
1011		require_clean_working_tree
1012	fi
1013	require_branch "$BRANCH"
1014
1015	git_local_branch_exists "$BASE_BRANCH" || die "The base '$BASE_BRANCH' doesn't exists locally or is not a branch. Can't rebase the release branch '$BRANCH'."
1016
1017	git_do checkout -q "$BRANCH"  || die "Could not check out branch '$BRANCH'."
1018	if flag interactive; then
1019		opts="$opts -i"
1020	fi
1021	if flag preserve_merges; then
1022		opts="$opts -p"
1023	fi
1024	git_do rebase $opts "$BASE_BRANCH"
1025}
1026
1027cmd_delete() {
1028	OPTIONS_SPEC="\
1029git flow release delete [-h] [-f] [-r] <name>
1030
1031Delete the given release branch
1032--
1033h,help           Show this help
1034showcommands!    Show git commands while executing them
1035f,[no]force      Force deletion
1036r,[no]remote     Delete remote branch
1037"
1038	local current_branch
1039
1040	# Define flags
1041	DEFINE_boolean 'force' false "force deletion" f
1042	DEFINE_boolean 'remote' false "delete remote branch" r
1043
1044	# Override defaults with values from config
1045	gitflow_override_flag_boolean   "release.delete.fetch"    "fetch"
1046	gitflow_override_flag_boolean   "release.delete.remote"   "remote"
1047
1048	# Parse arguments
1049	parse_args "$@"
1050
1051	gitflow_require_version_arg
1052
1053	# Sanity checks
1054	require_branch "$BRANCH"
1055
1056	BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
1057	BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH}
1058
1059	run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH"
1060
1061	current_branch=$(git_current_branch)
1062	# We can't delete a branch we are on, switch to the develop branch.
1063	if [ "$BRANCH" = "$current_branch" ]; then
1064		require_clean_working_tree
1065		if git_local_branch_exists "$BASE_BRANCH"; then
1066			git_do checkout "$BASE_BRANCH"
1067		else
1068			git_do checkout "$DEVELOP_BRANCH" || die "Could not check out branch '$DEVELOP_BRANCH'."
1069		fi
1070	fi
1071
1072	if ( git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH" && git_is_branch_merged_into "$BRANCH" "$BASE_BRANCH" ); then
1073		git_do branch -d "$BRANCH" || die "Could not delete the $BRANCH."
1074		if flag remote; then
1075			git_remote_branch_delete "$BRANCH"
1076		fi
1077	else
1078		if flag force; then
1079			git_do branch -D "$BRANCH" || die "Could not delete the $BRANCH."
1080			if flag remote; then
1081				git_remote_branch_delete "$BRANCH"
1082			fi
1083		else
1084			die "Release branch '$BRANCH' has been not been merged in branch '$MASTER_BRANCH' and/or branch '$BASE_BRANCH'. Use -f to force the deletion."
1085		fi
1086	fi
1087
1088	gitflow_config_remove_base_section "$BRANCH"
1089	run_post_hook "$VERSION" "$ORIGIN" "$BRANCH"
1090
1091	echo
1092	echo "Summary of actions:"
1093	echo "- Release branch '$BRANCH' has been deleted."
1094	flag remote && echo "- Release branch '$BRANCH' in '$ORIGIN' has been deleted."
1095	echo "- You are now on branch '$(git_current_branch)'"
1096	echo
1097}
1098