744 lines
24 KiB
Bash
744 lines
24 KiB
Bash
# $Id$
|
|
# vim:et:ft=sh:sts=2:sw=2
|
|
#
|
|
# git-flow -- A collection of Git extensions to provide high-level
|
|
# repository operations for Vincent Driessen's branching model.
|
|
#
|
|
# A blog post presenting this model is found at:
|
|
# http://blog.avirtualhome.com/development-workflow-using-git/
|
|
#
|
|
# Feel free to contribute to this project at:
|
|
# http://github.com/petervanderdoes/gitflow
|
|
#
|
|
# Authors:
|
|
# Copyright 2012-2019 Peter van der Does. All rights reserved.
|
|
#
|
|
# Original Author:
|
|
# Copyright 2010 Vincent Driessen. All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions are met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
# list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
# this list of conditions and the following disclaimer in the documentation
|
|
# and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
|
|
initialize() {
|
|
require_git_repo
|
|
require_gitflow_initialized
|
|
git config --get gitflow.prefix.hotfix >/dev/null 2>&1 || die "Hotfix prefix not set. Please run 'git flow init'."
|
|
gitflow_load_settings
|
|
VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
|
|
PREFIX=$(git config --get gitflow.prefix.hotfix)
|
|
}
|
|
|
|
usage() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix [list]
|
|
git flow hotfix start
|
|
git flow hotfix finish
|
|
git flow hotfix publish
|
|
git flow hotfix delete
|
|
|
|
Manage your hotfix branches.
|
|
|
|
For more specific help type the command followed by --help
|
|
--
|
|
"
|
|
flags_help
|
|
}
|
|
|
|
cmd_default() {
|
|
cmd_list "$@"
|
|
}
|
|
|
|
cmd_list() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix [list] [-h] [-v]
|
|
|
|
Lists all local hotfix branches
|
|
--
|
|
h,help! Show this help
|
|
v,verbose! Verbose (more) output
|
|
"
|
|
local hotfix_branches current_branch width branch len
|
|
local base master_sha branch_sha
|
|
|
|
# Define flags
|
|
DEFINE_boolean 'verbose' false 'verbose (more) output' v
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
hotfix_branches=$(git_local_branches_prefixed "$PREFIX")
|
|
if [ -z "$hotfix_branches" ]; then
|
|
warn "No hotfix branches exist."
|
|
warn ""
|
|
warn "You can start a new hotfix branch:"
|
|
warn ""
|
|
warn " git flow hotfix start <version> [<base>]"
|
|
warn ""
|
|
exit 0
|
|
fi
|
|
current_branch=$(git_current_branch)
|
|
|
|
# Determine column width first
|
|
width=0
|
|
for branch in $hotfix_branches; do
|
|
len=${#branch}
|
|
width=$(max $width $len)
|
|
done
|
|
width=$(($width+3-${#PREFIX}))
|
|
|
|
for branch in $hotfix_branches; do
|
|
base=$(git merge-base "$branch" "$MASTER_BRANCH")
|
|
master_sha=$(git rev-parse "$MASTER_BRANCH")
|
|
branch_sha=$(git rev-parse "$branch")
|
|
if [ "$branch" = "$current_branch" ]; then
|
|
printf "* "
|
|
else
|
|
printf " "
|
|
fi
|
|
if flag verbose; then
|
|
printf "%-${width}s" "${branch#$PREFIX}"
|
|
if [ "$branch_sha" = "$master_sha" ]; then
|
|
printf "(no commits yet)"
|
|
else
|
|
local tagname=$(git name-rev --tags --no-undefined --name-only "$base")
|
|
local nicename
|
|
if [ "$tagname" != "" ]; then
|
|
nicename=$tagname
|
|
else
|
|
nicename=$(git rev-parse --short "$base")
|
|
fi
|
|
printf "(based on $nicename)"
|
|
fi
|
|
else
|
|
printf "%s" "${branch#$PREFIX}"
|
|
fi
|
|
echo
|
|
done
|
|
}
|
|
|
|
cmd_help() {
|
|
usage
|
|
exit 0
|
|
}
|
|
|
|
# Parse arguments and set common variables
|
|
parse_args() {
|
|
FLAGS "$@" || exit $?
|
|
eval set -- "${FLAGS_ARGV}"
|
|
|
|
# Read arguments into global variables
|
|
if [ -z $1 ]; then
|
|
VERSION=''
|
|
else
|
|
VERSION=$1
|
|
fi
|
|
BRANCH=$PREFIX$VERSION
|
|
}
|
|
|
|
require_no_existing_hotfix_branches() {
|
|
local hotfix_branches first_branch
|
|
|
|
hotfix_branches=$(git_local_branches_prefixed "$PREFIX")
|
|
first_branch=$(echo ${hotfix_branches} | head -n1)
|
|
|
|
first_branch=${first_branch#$PREFIX}
|
|
[ -z "$hotfix_branches" ] || die "There is an existing hotfix branch '$first_branch'. Finish that one first."
|
|
}
|
|
|
|
cmd_start() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix start [-h] [-F] <version> [<base>]
|
|
|
|
Start new hotfix branch named <version>, optionally base it on <base> instead of the <master> branch
|
|
--
|
|
h,help! Show this help
|
|
showcommands! Show git commands while executing them
|
|
F,[no]fetch Fetch from origin before performing local operation
|
|
"
|
|
local base
|
|
|
|
# Define flags
|
|
DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F
|
|
|
|
# Override defaults with values from config
|
|
gitflow_override_flag_boolean "hotfix.start.fetch" "fetch"
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
eval set -- "${FLAGS_ARGV}"
|
|
base=${2:-$MASTER_BRANCH}
|
|
|
|
# No need to continue if not clean
|
|
require_base_is_local_branch "$base"
|
|
git_config_bool_exists "gitflow.allowdirty" || require_clean_working_tree
|
|
|
|
# Update the local repo with remote changes, if asked
|
|
if flag fetch; then
|
|
git_fetch_branch "$ORIGIN" "$base"
|
|
fi
|
|
|
|
# Run filter on the version
|
|
VERSION=$(run_filter_hook hotfix-start-version $VERSION)
|
|
if [ $? -eq 127 ]; then
|
|
die $VERSION
|
|
fi
|
|
|
|
# As VERSION might have changed reset BRANCH with new VERSION
|
|
BRANCH=$PREFIX$VERSION
|
|
|
|
gitflow_require_version_arg
|
|
if ! $(git config --bool --get gitflow.multi-hotfix 2>&1); then
|
|
require_no_existing_hotfix_branches
|
|
fi
|
|
|
|
# Sanity checks
|
|
require_branch_absent "$BRANCH"
|
|
require_tag_absent "$VERSION_PREFIX$VERSION"
|
|
if git_remote_branch_exists "$ORIGIN/$base"; then
|
|
require_branches_equal "$base" "$ORIGIN/$base"
|
|
fi
|
|
|
|
run_pre_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH" "$base"
|
|
|
|
gitflow_config_set_base_branch $base $BRANCH
|
|
|
|
# Create branch
|
|
git_do checkout -b "$BRANCH" "$base" || die "Could not create hotfix branch '$BRANCH'."
|
|
|
|
run_post_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH" "$base"
|
|
|
|
echo
|
|
echo "Summary of actions:"
|
|
echo "- A new branch '$BRANCH' was created, based on '$base'"
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
echo "Follow-up actions:"
|
|
echo "- Start committing your hot fixes"
|
|
echo "- Bump the version number now!"
|
|
echo "- When done, run:"
|
|
echo
|
|
echo " git flow hotfix finish '$VERSION'"
|
|
echo
|
|
}
|
|
|
|
cmd_publish() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix publish [-h] <version>
|
|
|
|
Start sharing hotfix <name> on $ORIGIN
|
|
--
|
|
h,help! Show this help
|
|
showcommands! Show git commands while executing them
|
|
"
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
# Use current branch if no version is given
|
|
if [ "$VERSION" = "" ]; then
|
|
gitflow_use_current_branch_version
|
|
fi
|
|
|
|
# Sanity checks
|
|
require_clean_working_tree
|
|
require_branch "$BRANCH"
|
|
git_do fetch -q "$ORIGIN" || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'."
|
|
require_branch_absent "$ORIGIN/$BRANCH"
|
|
|
|
run_pre_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
# Create remote branch with remote tracking
|
|
git_do push -u "$ORIGIN" "$BRANCH:$BRANCH"
|
|
git_do fetch -q "$ORIGIN" "$BRANCH" || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'."
|
|
git_do checkout "$BRANCH" || die "Could not check out branch '$BRANCH'."
|
|
|
|
run_post_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
echo
|
|
echo "Summary of actions:"
|
|
echo "- The remote branch '$BRANCH' was created or updated"
|
|
echo "- The local branch '$BRANCH' was configured to track the remote branch"
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
}
|
|
|
|
cmd_rebase() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix rebase [-h] [-i] [-p] [<name|nameprefix>]
|
|
|
|
Rebase <name> on <base_branch>
|
|
--
|
|
h,help! Show this help
|
|
showcommands! Show git commands while executing them
|
|
i,[no]interactive Do an interactive rebase
|
|
p,[no]preserve-merges Preserve merges
|
|
"
|
|
local opts
|
|
|
|
# Define flags
|
|
DEFINE_boolean 'interactive' false 'do an interactive rebase' i
|
|
DEFINE_boolean 'preserve-merges' false 'try to recreate merges' p
|
|
|
|
# Override defaults with values from config
|
|
gitflow_override_flag_boolean "hotfix.rebase.interactive" "interactive"
|
|
gitflow_override_flag_boolean "hotfix.rebase.preserve-merges" "preserve_merges"
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
# Use current branch if no version is given
|
|
if [ "$VERSION" = "" ]; then
|
|
gitflow_use_current_branch_version
|
|
fi
|
|
|
|
BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
|
|
BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH}
|
|
|
|
warn "Will try to rebase '$NAME' which is based on '$BASE_BRANCH'..."
|
|
if ! git_config_bool_exists "rebase.autostash"; then
|
|
require_clean_working_tree
|
|
fi
|
|
require_branch "$BRANCH"
|
|
|
|
git_local_branch_exists "$BASE_BRANCH" || die "The base '$BASE_BRANCH' doesn't exists locally or is not a branch. Can't rebase the hotfixe branch '$BRANCH'."
|
|
|
|
git_do checkout -q "$BRANCH" || die "Could not check out branch '$BRANCH'."
|
|
if flag interactive; then
|
|
opts="$opts -i"
|
|
fi
|
|
if flag preserve_merges; then
|
|
opts="$opts -p"
|
|
fi
|
|
git_do rebase $opts "$BASE_BRANCH"
|
|
}
|
|
|
|
cmd_track() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix track [-h] <version>
|
|
|
|
Create a tracking hotfix branch from $ORIGIN
|
|
--
|
|
h,help! Show this help
|
|
showcommands! Show git commands while executing them
|
|
"
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
gitflow_require_version_arg
|
|
|
|
# Sanity checks
|
|
require_clean_working_tree
|
|
require_branch_absent "$BRANCH"
|
|
git_do fetch -q "$ORIGIN"
|
|
require_branch "$ORIGIN/$BRANCH"
|
|
|
|
# Create tracking branch
|
|
git_do checkout -b "$BRANCH" "$ORIGIN/$BRANCH"
|
|
|
|
echo
|
|
echo "Summary of actions:"
|
|
echo "- A new remote tracking branch '$BRANCH' was created"
|
|
echo "- You are now on branch '$BRANCH'"
|
|
echo
|
|
}
|
|
|
|
cmd_finish() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix finish [-h] [-F] [-s] [-u] [-m | -f ] [-p] [-k] [-n] [-b] [-S] <version>
|
|
|
|
Finish hotfix branch <version>
|
|
--
|
|
h,help! Show this help
|
|
showcommands! Show git commands while executing them
|
|
F,[no]fetch Fetch from origin before performing finish
|
|
s,[no]sign Sign the release tag cryptographically
|
|
u,[no]signingkey Use the given GPG-key for the digital signature (implies -s)
|
|
m,[no]message Use the given tag message
|
|
f,[no]messagefile= Use the contents of the given file as tag message
|
|
p,[no]push Push to origin after performing finish
|
|
k,[no]keep Keep branch after performing finish
|
|
[no]keepremote Keep the remote branch
|
|
[no]keeplocal Keep the local branch
|
|
D,[no]force_delete Force delete hotfix branch after finish
|
|
n,[no]notag Don't tag this hotfix
|
|
b,[no]nobackmerge Don't back-merge master, or tag if applicable, in develop
|
|
S,[no]squash Squash hotfix during merge
|
|
T,tagname! Use given tag name
|
|
"
|
|
local opts commit keepmsg remotebranchdeleted localbranchdeleted
|
|
|
|
# Define flags
|
|
DEFINE_boolean 'fetch' false "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
|
|
DEFINE_string 'messagefile' "" "use the contents of the given file as tag message" f
|
|
DEFINE_boolean 'push' false "push to $ORIGIN after performing finish" p
|
|
DEFINE_boolean 'keep' false "keep branch after performing finish" k
|
|
DEFINE_boolean 'keepremote' false "keep the remote branch"
|
|
DEFINE_boolean 'keeplocal' false "keep the local branch"
|
|
DEFINE_boolean 'force_delete' false "force delete hotfix branch after finish" D
|
|
DEFINE_boolean 'notag' false "don't tag this hotfix" n
|
|
DEFINE_boolean 'nobackmerge' false "don't back-merge $MASTER_BRANCH, or tag if applicable, in $DEVELOP_BRANCH " b
|
|
DEFINE_boolean 'squash' false "squash release during merge" S
|
|
DEFINE_boolean 'squash-info' false "add branch info during squash"
|
|
DEFINE_string 'tagname' "" "use the given tag name" T
|
|
|
|
# Override defaults with values from config
|
|
gitflow_override_flag_boolean "hotfix.finish.fetch" "fetch"
|
|
gitflow_override_flag_boolean "hotfix.finish.sign" "sign"
|
|
gitflow_override_flag_boolean "hotfix.finish.push" "push"
|
|
gitflow_override_flag_boolean "hotfix.finish.keep" "keep"
|
|
gitflow_override_flag_boolean "hotfix.finish.keepremote" "keepremote"
|
|
gitflow_override_flag_boolean "hotfix.finish.keeplocal" "keeplocal"
|
|
gitflow_override_flag_boolean "hotfix.finish.force-delete" "force_delete"
|
|
gitflow_override_flag_boolean "hotfix.finish.notag" "notag"
|
|
gitflow_override_flag_boolean "hotfix.finish.nobackmerge" "nobackmerge"
|
|
gitflow_override_flag_boolean "hotfix.finish.squash" "squash"
|
|
gitflow_override_flag_boolean "hotfix.finish.squash-info" "squash_info"
|
|
gitflow_override_flag_string "hotfix.finish.signingkey" "signingkey"
|
|
gitflow_override_flag_string "hotfix.finish.message" "message"
|
|
gitflow_override_flag_string "hotfix.finish.messagefile" "messagefile"
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
# Use current branch if no version is given
|
|
if [ "$VERSION" = "" ]; then
|
|
gitflow_use_current_branch_version
|
|
fi
|
|
|
|
# Use branch name if no tag name is given
|
|
if [ "$FLAGS_tagname" != "" ]; then
|
|
TAGNAME=$FLAGS_tagname
|
|
else
|
|
TAGNAME=$VERSION
|
|
fi
|
|
|
|
remotebranchdeleted=$FLAGS_FALSE
|
|
localbranchdeleted=$FLAGS_FALSE
|
|
|
|
# Handle flags that imply other flags
|
|
if [ "$FLAGS_signingkey" != "" ]; then
|
|
FLAGS_sign=$FLAGS_TRUE
|
|
fi
|
|
|
|
# Keeping both branches implies the --keep flag to be true.
|
|
if flag keepremote && flag keeplocal; then
|
|
FLAGS_keep=$FLAGS_TRUE
|
|
fi
|
|
|
|
# Sanity checks
|
|
require_branch "$BRANCH"
|
|
require_clean_working_tree
|
|
|
|
BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
|
|
BASE_BRANCH=${BASE_BRANCH:-$MASTER_BRANCH}
|
|
git_local_branch_exists "$BASE_BRANCH" || die "The base '$BASE_BRANCH' doesn't exists locally or is not a branch. Can't finish the hotfix branch '$BRANCH'."
|
|
|
|
# We always fetch the Branch from Origin
|
|
# This is done to avoid possible commits on the remote that are not
|
|
# merged into the local branch
|
|
if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
|
|
git_fetch_branch "$ORIGIN" "$BRANCH"
|
|
fi
|
|
|
|
# Update local branches with remote branches
|
|
if flag fetch; then
|
|
git_fetch_branch "$ORIGIN" "$BASE_BRANCH"
|
|
[ "$BASE_BRANCH" = "$MASTER_BRANCH" ] && git_fetch_branch "$ORIGIN" "$DEVELOP_BRANCH"
|
|
fi
|
|
|
|
# Check if the local branches have all the commits from the remote branches
|
|
if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
|
|
require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH"
|
|
fi
|
|
if git_remote_branch_exists "$ORIGIN/$BASE_BRANCH"; then
|
|
require_branches_equal "$BASE_BRANCH" "$ORIGIN/$BASE_BRANCH"
|
|
fi
|
|
if [ "$BASE_BRANCH" = "$MASTER_BRANCH" ]; then
|
|
if git_remote_branch_exists "$ORIGIN/$DEVELOP_BRANCH"; then
|
|
require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
|
|
fi
|
|
fi
|
|
|
|
# If the branch is already merged there is no need to check the hotfix branch
|
|
# This can happen when the merge in develop fails and we rerun the finish.
|
|
if ! git_is_branch_merged_into "$BRANCH" "$BASE_BRANCH"; then
|
|
# Check if the hotfix branch:
|
|
# - has commits: No reason to finish a hotfix without commits
|
|
# - Is ahead of the BASE: If it's not a good idea to merge
|
|
# - Can be merged: If there's no common ancestor we can't merge the hotfix
|
|
git_compare_refs "$BRANCH" "$BASE_BRANCH"
|
|
case $? in
|
|
0)
|
|
die "You need some commits in the hotfix branch '$BRANCH'"
|
|
;;
|
|
1)
|
|
die "The hotfix branch '$BRANCH' is not ahead of branch '$BASE_BRANCH'"
|
|
;;
|
|
4)
|
|
die "The hotfix branch '$BRANCH' has no common ancestor with branch '$BASE_BRANCH'"
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
if noflag notag; then
|
|
# We ask for a tag, be sure it does not exists or
|
|
# points to the latest hotfix commit
|
|
if git_tag_exists "$VERSION_PREFIX$TAGNAME"; then
|
|
git_compare_refs "$BRANCH" "$VERSION_PREFIX$TAGNAME"^2 2>/dev/null
|
|
[ $? -eq 0 ] || die "Tag already exists and does not point to hotfix branch '$BRANCH'"
|
|
fi
|
|
fi
|
|
|
|
run_pre_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
|
|
|
|
# Try to merge into BASE.
|
|
# In case a previous attempt to finish this release branch has failed,
|
|
# but the merge into BASE was successful, we skip it now
|
|
if ! git_is_branch_merged_into "$BRANCH" "$BASE_BRANCH"; then
|
|
git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'."
|
|
if noflag squash; then
|
|
git_do merge --no-ff "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now?
|
|
else
|
|
git_do merge --squash "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now?
|
|
flag squash_info && gitflow_create_squash_message "Merged hotfix branch '$BRANCH'" "$BASE_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG"
|
|
git_do commit
|
|
fi
|
|
fi
|
|
|
|
if noflag notag; then
|
|
# 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
|
|
if ! git_tag_exists "$VERSION_PREFIX$TAGNAME"; then
|
|
if [ "$FLAGS_message" != "" ] && [ "$FLAGS_messagefile" != "" ]; then
|
|
die "Use either -m,--message or -f,--messagefile. Can not use both options at the same time"
|
|
fi
|
|
opts="-a"
|
|
flag sign && opts="$opts -s"
|
|
[ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
|
|
if [ "$FLAGS_message" != "" ]; then
|
|
# Run filter on the tag message
|
|
FLAGS_message=$(run_filter_hook hotfix-finish-tag-message "${FLAGS_message}" "$VERSION_PREFIX$TAGNAME")
|
|
opts="$opts -m '$FLAGS_message'"
|
|
fi
|
|
[ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'"
|
|
eval git_do tag $opts "$VERSION_PREFIX$TAGNAME" || die "Tagging failed. Please run finish again to retry."
|
|
fi
|
|
fi
|
|
|
|
if [ "$BASE_BRANCH" = "$MASTER_BRANCH" ]; then
|
|
# By default we back-merge the $MASTER_BRANCH unless the user explicitly
|
|
# stated not to do a back-merge, in that case we use the $BRANCH.
|
|
if noflag nobackmerge; then
|
|
MERGE_BRANCH="$BASE_BRANCH"
|
|
else
|
|
MERGE_BRANCH="$BRANCH"
|
|
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 ! git_is_branch_merged_into "$MERGE_BRANCH" "$DEVELOP_BRANCH"; then
|
|
git_do checkout "$DEVELOP_BRANCH" || die "Could not check out branch '$DEVELOP_BRANCH'."
|
|
|
|
if noflag nobackmerge; then
|
|
# Accounting for 'git describe', if a release is tagged
|
|
# we use the tag commit instead of the branch.
|
|
if noflag notag; then
|
|
commit="$VERSION_PREFIX$TAGNAME"
|
|
else
|
|
commit="$BASE_BRANCH"
|
|
fi
|
|
else
|
|
commit="$BRANCH"
|
|
fi
|
|
|
|
git_do merge --no-ff "$commit" || die "There were merge conflicts."
|
|
# TODO: What do we do now?
|
|
fi
|
|
fi
|
|
|
|
run_post_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
|
|
|
|
if flag push; then
|
|
if [ "$BASE_BRANCH" = "$MASTER_BRANCH" ]; then
|
|
git_do push "$ORIGIN" "$DEVELOP_BRANCH" || die "Could not push branch '$DEVELOP_BRANCH' to remote '$ORIGIN'."
|
|
fi
|
|
git_do push "$ORIGIN" "$BASE_BRANCH" || die "Could not push branch '$BASE_BRANCH' to remote '$ORIGIN'."
|
|
if noflag notag; then
|
|
git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'."
|
|
fi
|
|
fi
|
|
|
|
# Delete branch
|
|
if noflag keep; then
|
|
|
|
# Always delete remote first
|
|
if noflag keepremote;then
|
|
if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
|
|
git_remote_branch_delete "$BRANCH" && remotebranchdeleted=$FLAGS_TRUE
|
|
fi
|
|
fi
|
|
|
|
# Delete local after remote to avoid warnings
|
|
if noflag keeplocal; then
|
|
if [ "$BRANCH" = "$(git_current_branch)" ]; then
|
|
git_do checkout "$DEVELOP_BRANCH" || die "Could not check out branch '$DEVELOP_BRANCH'."
|
|
fi
|
|
if flag force_delete; then
|
|
git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
|
|
else
|
|
git_do branch -d "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
|
|
fi
|
|
fi
|
|
|
|
# no more branches: we can safely remove config section
|
|
if ! git_remote_branch_exists "$ORIGIN/$BRANCH" -a ! git_local_branch_exists "$BRANCH"; then
|
|
gitflow_config_remove_base_section "$BRANCH"
|
|
fi
|
|
|
|
fi
|
|
|
|
echo
|
|
echo "Summary of actions:"
|
|
if flag fetch; then
|
|
echo "- Latest objects have been fetched from '$ORIGIN'"
|
|
fi
|
|
echo "- Hotfix branch '$BRANCH' has been merged into '$BASE_BRANCH'"
|
|
if noflag notag; then
|
|
echo "- The hotfix was tagged '$VERSION_PREFIX$TAGNAME'"
|
|
fi
|
|
if [ "$BASE_BRANCH" = "$MASTER_BRANCH" ]; then
|
|
[ "$commit" = "$BASE_BRANCH" ] && echo "- Master branch '$BASE_BRANCH' has been back-merged into '$DEVELOP_BRANCH'"
|
|
[ "$commit" = "$VERSION_PREFIX$TAGNAME" ] && echo "- Hotfix tag '$VERSION_PREFIX$TAGNAME' has been back-merged into '$DEVELOP_BRANCH'"
|
|
[ "$commit" = "$BRANCH" ] && echo "- Hotfix branch '$BRANCH' has been merged into '$DEVELOP_BRANCH'"
|
|
fi
|
|
if noflag keep; then
|
|
if [ $localbranchdeleted -eq $FLAGS_TRUE ]; then
|
|
keepmsg="has been locally deleted"
|
|
else
|
|
keepmsg="is still locally available"
|
|
fi
|
|
if [ $remotebranchdeleted -eq $FLAGS_TRUE ]; then
|
|
keepmsg=$keepmsg"; it has been remotely deleted from '$ORIGIN'"
|
|
elif git_remote_branch_exists "$ORIGIN/$BRANCH"; then
|
|
keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'"
|
|
fi
|
|
else
|
|
keepmsg="is still locally available"
|
|
if git_remote_branch_exists "$ORIGIN/$BRANCH"; then
|
|
keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'"
|
|
fi
|
|
fi
|
|
echo "- Hotfix branch '$BRANCH' "$keepmsg
|
|
if flag push; then
|
|
if [ "$BASE_BRANCH" = "$MASTER_BRANCH" ]; then
|
|
echo "- '$DEVELOP_BRANCH', '$BASE_BRANCH' and tags have been pushed to '$ORIGIN'"
|
|
else
|
|
echo "- '$BASE_BRANCH' and tags have been pushed to '$ORIGIN'"
|
|
fi
|
|
fi
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
|
|
}
|
|
|
|
cmd_delete() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix delete [-h] [-f] [-r] <name>
|
|
|
|
Delete the given hotfix branch
|
|
--
|
|
h,help! Show this help
|
|
showcommands! Show git commands while executing them
|
|
f,[no]force Force deletion
|
|
r,[no]remote Delete remote branch
|
|
"
|
|
local current_branch
|
|
|
|
# Define flags
|
|
DEFINE_boolean 'force' false "force deletion" f
|
|
DEFINE_boolean 'remote' false "delete remote branch" r
|
|
|
|
# Override defaults with values from config
|
|
gitflow_override_flag_boolean "hotfix.delete.force" "force"
|
|
gitflow_override_flag_boolean "hotfix.finish.remote" "remote"
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
gitflow_require_version_arg
|
|
|
|
# Sanity checks
|
|
require_branch "$BRANCH"
|
|
|
|
run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
current_branch=$(git_current_branch)
|
|
# We can't delete a branch we are on, switch to the master branch.
|
|
if [ "$BRANCH" = "$current_branch" ]; then
|
|
require_clean_working_tree
|
|
git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
|
|
fi
|
|
|
|
if ( git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH" && git_is_branch_merged_into "$BRANCH" "$DEVELOP_BRANCH" ); then
|
|
git_do branch -d "$BRANCH" || die "Could not delete the $BRANCH."
|
|
if flag remote; then
|
|
git_remote_branch_delete "$BRANCH"
|
|
fi
|
|
else
|
|
if flag force; then
|
|
git_do branch -D "$BRANCH" || die "Could not delete the $BRANCH."
|
|
if flag remote; then
|
|
git_remote_branch_delete "$BRANCH"
|
|
fi
|
|
else
|
|
die "Hotfix branch '$BRANCH' has been not been merged in branch '$MASTER_BRANCH' and/or branch '$DEVELOP_BRANCH'. Use -f to force the deletion."
|
|
fi
|
|
fi
|
|
|
|
gitflow_config_remove_base_section "$BRANCH"
|
|
run_post_hook "$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
echo
|
|
echo "Summary of actions:"
|
|
echo "- Hotfix branch '$BRANCH' has been deleted."
|
|
flag remote && echo "- Hotfix branch '$BRANCH' in '$ORIGIN' has been deleted."
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
}
|
|
|
|
cmd_rename() {
|
|
OPTIONS_SPEC="\
|
|
git flow hotfix rename <new_name> [<new_name>]
|
|
|
|
Rename a given hotfix branch
|
|
--
|
|
h,help! Show this help
|
|
showcommands! Show git commands while executing them
|
|
"
|
|
gitflow_rename_branch "$@"
|
|
}
|