Merge branch 'feature/annotated-signed-tags' into develop
diff --git a/git-flow-hotfix b/git-flow-hotfix
index 7ffa39b..4333e30 100644
--- a/git-flow-hotfix
+++ b/git-flow-hotfix
@@ -113,7 +113,7 @@
 }
 
 cmd_start() {
-	DEFINE_boolean fetch true "fetch from $ORIGIN before finishing hotfix" F
+	DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
 	parse_args "$@"
 	BASE="${2:-$MASTER_BRANCH}"
 	require_version_arg
@@ -121,11 +121,12 @@
 
 	# sanity checks
 	gitflow_require_clean_working_tree
+	gitflow_require_branch_absent $BRANCH
+	gitflow_require_tag_absent $VERSION_PREFIX$VERSION
 	if flag fetch; then
 		git fetch -q $ORIGIN $MASTER_BRANCH
 	fi
 	gitflow_require_branches_equal $MASTER_BRANCH $ORIGIN/$MASTER_BRANCH
-	gitflow_require_branch_absent $BRANCH
 
 	# create branch
 	git checkout -b $BRANCH $BASE
@@ -145,27 +146,67 @@
 }
 
 cmd_finish() {
-	DEFINE_boolean fetch true "fetch from $ORIGIN before finishing hotfix" F
+	DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
+	DEFINE_boolean sign false "sign the release tag cryptographically" s
+	DEFINE_string signingkey "" "use the given GPG-key for the digital signature (implies -s)" u
+	DEFINE_string message "" "use the given tag message" m
 	parse_args "$@"
 	require_version_arg
 
+	# handle flags that imply other flags
+	if [ "$FLAGS_signingkey" != "" ]; then
+		FLAGS_sign=$FLAGS_TRUE
+	fi
+
 	# sanity checks
+	gitflow_require_branch $BRANCH
 	gitflow_require_clean_working_tree
 	if flag fetch; then
-		git fetch -q $ORIGIN $MASTER_BRANCH
-		git fetch -q $ORIGIN $DEVELOP_BRANCH
+		git fetch -q $ORIGIN $MASTER_BRANCH || \
+		  die "Could not fetch $MASTER_BRANCH from $ORIGIN."
+		git fetch -q $ORIGIN $DEVELOP_BRANCH || \
+		  die "Could not fetch $DEVELOP_BRANCH from $ORIGIN."
 	fi
 	gitflow_require_branches_equal $MASTER_BRANCH $ORIGIN/$MASTER_BRANCH
 	gitflow_require_branches_equal $DEVELOP_BRANCH $ORIGIN/$DEVELOP_BRANCH
 
-	# merge into master
-	git checkout $MASTER_BRANCH
-	git merge --no-ff $BRANCH
-	git tag $VERSION_PREFIX$VERSION
+	# try to merge into master
+	# in case a previous attempt to finish this release branch has failed,
+	# but the merge into master was successful, we skip it now
+	if ! gitflow_is_branch_merged_into $BRANCH $MASTER_BRANCH; then
+		git checkout $MASTER_BRANCH || \
+		  die "Could not check out $MASTER_BRANCH."
+		git merge --no-ff $BRANCH || \
+		  die "There were merge conflicts."
+		  # TODO: What do we do now?
+	fi
 
-	# merge into develop if we fixed a master issue
-	git checkout $DEVELOP_BRANCH
-	git merge --no-ff $BRANCH
+	# try to tag the release
+	# in case a previous attempt to finish this release branch has failed,
+	# but the tag was set successful, we skip it now
+	typeset tagname=$VERSION_PREFIX$VERSION
+	if ! gitflow_tag_exists $tagname; then
+		typeset opts="-a"
+		flag sign && opts="$opts -s"
+		[ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
+		[ "$FLAGS_message" != "" ] && opts="$opts -m '$FLAGS_message'"
+		git tag $opts "$VERSION_PREFIX$VERSION" || \
+		  die "Tagging failed. Please run finish again to retry."
+	fi
+
+	# try to merge into develop
+	# in case a previous attempt to finish this release branch has failed,
+	# but the merge into develop was successful, we skip it now
+	if ! gitflow_is_branch_merged_into $BRANCH $DEVELOP_BRANCH; then
+		git checkout $DEVELOP_BRANCH || \
+		  die "Could not check out $DEVELOP_BRANCH."
+
+		# TODO: Actually, accounting for 'git describe' pays, so we should
+		# ideally git merge --no-ff $tagname here, instead!
+		git merge --no-ff $BRANCH || \
+		  die "There were merge conflicts."
+		  # TODO: What do we do now?
+	fi
 
 	# delete branch
 	git branch -d $BRANCH
diff --git a/git-flow-release b/git-flow-release
index 8fb4061..9750cc8 100644
--- a/git-flow-release
+++ b/git-flow-release
@@ -127,11 +127,12 @@
 
 	# sanity checks
 	gitflow_require_clean_working_tree
+	gitflow_require_branch_absent $BRANCH
+	gitflow_require_tag_absent $VERSION_PREFIX$VERSION
 	if flag fetch; then
 		git fetch -q $ORIGIN $DEVELOP_BRANCH
 	fi
 	gitflow_require_branches_equal $DEVELOP_BRANCH $ORIGIN/$DEVELOP_BRANCH
-	gitflow_require_branch_absent $BRANCH
 
 	# create branch
 	git checkout -b $BRANCH $BASE
@@ -152,26 +153,66 @@
 
 cmd_finish() {
 	DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
+	DEFINE_boolean sign false "sign the release tag cryptographically" s
+	DEFINE_string signingkey "" "use the given GPG-key for the digital signature (implies -s)" u
+	DEFINE_string message "" "use the given tag message" m
 	parse_args "$@"
 	require_version_arg
 
+	# handle flags that imply other flags
+	if [ "$FLAGS_signingkey" != "" ]; then
+		FLAGS_sign=$FLAGS_TRUE
+	fi
+
 	# sanity checks
+	gitflow_require_branch $BRANCH
 	gitflow_require_clean_working_tree
 	if flag fetch; then
-		git fetch -q $ORIGIN $MASTER_BRANCH
-		git fetch -q $ORIGIN $DEVELOP_BRANCH
+		git fetch -q $ORIGIN $MASTER_BRANCH || \
+		  die "Could not fetch $MASTER_BRANCH from $ORIGIN."
+		git fetch -q $ORIGIN $DEVELOP_BRANCH || \
+		  die "Could not fetch $DEVELOP_BRANCH from $ORIGIN."
 	fi
 	gitflow_require_branches_equal $MASTER_BRANCH $ORIGIN/$MASTER_BRANCH
 	gitflow_require_branches_equal $DEVELOP_BRANCH $ORIGIN/$DEVELOP_BRANCH
 
-	# merge into master
-	git checkout $MASTER_BRANCH
-	git merge --no-ff $BRANCH
-	git tag $VERSION_PREFIX$VERSION
+	# try to merge into master
+	# in case a previous attempt to finish this release branch has failed,
+	# but the merge into master was successful, we skip it now
+	if ! gitflow_is_branch_merged_into $BRANCH $MASTER_BRANCH; then
+		git checkout $MASTER_BRANCH || \
+		  die "Could not check out $MASTER_BRANCH."
+		git merge --no-ff $BRANCH || \
+		  die "There were merge conflicts."
+		  # TODO: What do we do now?
+	fi
 
-	# merge into develop
-	git checkout $DEVELOP_BRANCH
-	git merge --no-ff $BRANCH
+	# try to tag the release
+	# in case a previous attempt to finish this release branch has failed,
+	# but the tag was set successful, we skip it now
+	typeset tagname=$VERSION_PREFIX$VERSION
+	if ! gitflow_tag_exists $tagname; then
+		typeset opts="-a"
+		flag sign && opts="$opts -s"
+		[ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
+		[ "$FLAGS_message" != "" ] && opts="$opts -m '$FLAGS_message'"
+		git tag $opts "$tagname" || \
+		  die "Tagging failed. Please run finish again to retry."
+	fi
+
+	# try to merge into develop
+	# in case a previous attempt to finish this release branch has failed,
+	# but the merge into develop was successful, we skip it now
+	if ! gitflow_is_branch_merged_into $BRANCH $DEVELOP_BRANCH; then
+		git checkout $DEVELOP_BRANCH || \
+		  die "Could not check out $DEVELOP_BRANCH."
+
+		# TODO: Actually, accounting for 'git describe' pays, so we should
+		# ideally git merge --no-ff $tagname here, instead!
+		git merge --no-ff $BRANCH || \
+		  die "There were merge conflicts."
+		  # TODO: What do we do now?
+	fi
 
 	# delete branch
 	git branch -d $BRANCH
@@ -183,7 +224,7 @@
 	echo "Summary of actions:"
 	echo "- Latest objects have been fetched from '$ORIGIN'"
 	echo "- Release branch has been merged into '$MASTER_BRANCH'"
-	echo "- The release was tagged '$VERSION_PREFIX$VERSION'"
+	echo "- The release was tagged '$tagname'"
 	echo "- Release branch has been back-merged into '$DEVELOP_BRANCH'"
 	echo "- Release branch '$BRANCH' has been deleted"
 	echo
diff --git a/gitflow-common b/gitflow-common
index 2fbd8ec..4f2a85a 100644
--- a/gitflow-common
+++ b/gitflow-common
@@ -42,6 +42,7 @@
 LOCAL_BRANCHES=$(git branch | sed 's/^[* ] //')
 REMOTE_BRANCHES=$(git branch -r | sed 's/^[* ] //')
 ALL_BRANCHES="$LOCAL_BRANCHES $REMOTE_BRANCHES"
+ALL_TAGS=$(git tag)
 
 #
 # resolve_nameprefix
@@ -141,6 +142,16 @@
 	fi
 }
 
+gitflow_require_tag_absent() {
+	if has $1 $ALL_TAGS; then
+		die "Tag '$1' already exists. Pick another name."
+	fi
+}
+
+gitflow_tag_exists() {
+	has $1 $ALL_TAGS
+}
+
 #
 # gitflow_test_branches_equal()
 #