1098 lines
37 KiB
Bash
1098 lines
37 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.
|
|
#
|
|
|
|
#
|
|
# Function used by finish command to actually finish the release branch
|
|
# Called when the base of the release is the $DEVELOP_BRANCH
|
|
#
|
|
_finish_from_develop() {
|
|
local opts merge_branch commit keepmsg remotebranchdeleted localbranchdeleted compare_refs_result merge_result
|
|
|
|
remotebranchdeleted=$FLAGS_FALSE
|
|
localbranchdeleted=$FLAGS_FALSE
|
|
|
|
# Update local branches with remote branches
|
|
if flag fetch; then
|
|
git_fetch_branch "$ORIGIN" "$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/$MASTER_BRANCH"; then
|
|
if flag ff_master; then
|
|
git_compare_refs "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
|
|
compare_refs_result=$?
|
|
|
|
if [ $compare_refs_result -gt 0 ]; then
|
|
warn "Branches '"$MASTER_BRANCH"' and '"$ORIGIN/$MASTER_BRANCH"' have diverged."
|
|
if [ $compare_refs_result -eq 1 ]; then
|
|
warn "Fast forwarding '"$MASTER_BRANCH"'."
|
|
git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
|
|
git_do merge --ff-only "$ORIGIN/$MASTER_BRANCH" >/dev/null 2>&1
|
|
merge_result=$?
|
|
git_do checkout "$BRANCH"
|
|
if [ $merge_result -gt 0 ]; then
|
|
die "'"$MASTER_BRANCH"' can not be fast forwarded."
|
|
fi
|
|
elif [ $compare_refs_result -eq 2 ]; then
|
|
# Warn here, since there is no harm in being ahead
|
|
warn "And local branch '$1' is ahead of '$2'."
|
|
else
|
|
die "Branches need merging first."
|
|
fi
|
|
fi
|
|
else
|
|
require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
|
|
fi
|
|
fi
|
|
if git_remote_branch_exists "$ORIGIN/$DEVELOP_BRANCH"; then
|
|
require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
|
|
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 release branch '$BRANCH'"
|
|
fi
|
|
fi
|
|
|
|
run_pre_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
|
|
|
|
# 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 ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then
|
|
git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_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 release branch '$BRANCH'" "$MASTER_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
|
|
git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
|
|
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 release-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
|
|
|
|
# By default we backmerge 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="$MASTER_BRANCH"
|
|
else
|
|
merge_branch="$BRANCH"
|
|
fi
|
|
|
|
# Try to merge into develop unless 'nodevelopmerge' has been specified.
|
|
# In case a previous attempt to finish this release branch has failed,
|
|
# but the merge into develop was successful, we skip it now
|
|
if noflag nodevelopmerge; then
|
|
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="$MASTER_BRANCH"
|
|
fi
|
|
git_do merge --no-ff "$commit" || die "There were merge conflicts." # TODO: What do we do now?
|
|
else
|
|
commit="$BRANCH"
|
|
if noflag squash; then
|
|
git_do merge --no-ff "$commit" || die "There were merge conflicts." # TODO: What do we do now?
|
|
else
|
|
git_do merge --squash "$commit" || die "There were merge conflicts." # TODO: What do we do now?
|
|
flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$DEVELOP_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG"
|
|
git_do commit
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
run_post_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
|
|
|
|
if flag push; then
|
|
if flag pushdevelop; then
|
|
git_do push "$ORIGIN" "$DEVELOP_BRANCH" || die "Could not push branch '$DEVELOP_BRANCH' to remote '$ORIGIN'."
|
|
fi
|
|
if flag pushproduction; then
|
|
git_do push "$ORIGIN" "$MASTER_BRANCH" || die "Could not push branch '$MASTER_BRANCH' to remote '$ORIGIN'."
|
|
fi
|
|
if noflag notag && flag pushtag; then
|
|
git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'."
|
|
fi
|
|
fi
|
|
|
|
# Delete branch
|
|
if noflag keep; then
|
|
|
|
if [ "$BRANCH" = "$(git_current_branch)" ]; then
|
|
git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'."
|
|
fi
|
|
|
|
# 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 flag force_delete; then
|
|
git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
|
|
else
|
|
if noflag squash; then
|
|
git_do branch -d "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
|
|
else
|
|
git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE
|
|
fi
|
|
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 "- Release branch '$BRANCH' has been merged into '$MASTER_BRANCH'"
|
|
if noflag notag; then
|
|
echo "- The release was tagged '$VERSION_PREFIX$TAGNAME'"
|
|
fi
|
|
[ "$commit" = "$MASTER_BRANCH" ] && echo "- Master branch '$MASTER_BRANCH' has been back-merged into '$DEVELOP_BRANCH'"
|
|
[ "$commit" = "$VERSION_PREFIX$TAGNAME" ] && echo "- Release tag '$VERSION_PREFIX$TAGNAME' has been back-merged into '$DEVELOP_BRANCH'"
|
|
[ "$commit" = "$BRANCH" ] && echo "- Release branch '$BRANCH' has been merged into '$DEVELOP_BRANCH'"
|
|
|
|
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 "- Release branch '$BRANCH' "$keepmsg
|
|
|
|
if flag push; then
|
|
echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'"
|
|
fi
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
}
|
|
|
|
#
|
|
# Function used by finish command to actually finish the release branch
|
|
# Called when the base of the release is NOT the $DEVELOP_BRANCH
|
|
#
|
|
|
|
_finish_base() {
|
|
local opts merge_branch commit keepmsg localbranchdeleted remotebranchdeleted
|
|
|
|
remotebranchdeleted=$FLAGS_FALSE
|
|
localbranchdeleted=$FLAGS_FALSE
|
|
|
|
# Update local branches with remote branches
|
|
if flag fetch; then
|
|
git_fetch_branch "$ORIGIN" "$BASE_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 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 release branch '$BRANCH'"
|
|
fi
|
|
fi
|
|
|
|
run_pre_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
|
|
|
|
# Try to merge into base branch.
|
|
# 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 "$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 release 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
|
|
git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'."
|
|
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 release-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
|
|
|
|
run_post_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
|
|
|
|
# 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 "$BASE_BRANCH" || die "Could not check out branch '$BASE_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
|
|
|
|
if flag push; then
|
|
if flag pushdevelop; then
|
|
git_do push "$ORIGIN" "$BASE_BRANCH" || die "Could not push branch '$BASE_BRANCH' to remote '$ORIGIN'."
|
|
fi
|
|
if noflag notag && flag pushtag; then
|
|
git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'."
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
echo "Summary of actions:"
|
|
if flag fetch; then
|
|
echo "- Latest objects have been fetched from '$ORIGIN'"
|
|
fi
|
|
if noflag notag; then
|
|
echo "- The release was tagged '$VERSION_PREFIX$TAGNAME'"
|
|
fi
|
|
[ "$commit" = "$VERSION_PREFIX$TAGNAME" ] && echo "- Release tag '$VERSION_PREFIX$TAGNAME' has been merged into '$BASE_BRANCH'"
|
|
[ "$commit" = "$BRANCH" ] && echo "- Release branch '$BRANCH' has been merged into '$BASE_BRANCH'"
|
|
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 "- Release branch '$BRANCH' "$keepmsg
|
|
|
|
if flag push; then
|
|
echo "- '$BASE_BRANCH' and tags have been pushed to '$ORIGIN'"
|
|
fi
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
}
|
|
initialize() {
|
|
require_git_repo
|
|
require_gitflow_initialized
|
|
git config --get gitflow.prefix.release >/dev/null 2>&1 || die "Release 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.release)
|
|
}
|
|
|
|
usage() {
|
|
OPTIONS_SPEC="\
|
|
git flow release [list]
|
|
git flow release start
|
|
git flow release finish
|
|
git flow release publish
|
|
git flow release track
|
|
git flow release delete
|
|
|
|
Manage your release branches.
|
|
|
|
For more specific help type the command followed by --help
|
|
--
|
|
"
|
|
flags_help
|
|
}
|
|
|
|
cmd_default() {
|
|
cmd_list "$@"
|
|
}
|
|
|
|
cmd_list() {
|
|
OPTIONS_SPEC="\
|
|
git flow release [list] [-h] [-v]
|
|
|
|
List existing release branches
|
|
--
|
|
h,help! Show this help
|
|
v,verbose! verbose (more) output
|
|
"
|
|
local release_branches current_branch
|
|
local width branch len
|
|
local base develop_sha branch_sha nicename
|
|
|
|
# cmd_default may already define flags
|
|
# at this stage we can not use parse_args
|
|
if [ -z "${FLAGS_verbose}" ]; then
|
|
DEFINE_boolean 'verbose' false 'verbose (more) output' v
|
|
fi
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
release_branches=$(git_local_branches_prefixed "$PREFIX")
|
|
if [ -z "$release_branches" ]; then
|
|
warn "No release branches exist."
|
|
warn ""
|
|
warn "You can start a new release branch:"
|
|
warn ""
|
|
warn " git flow release start <name> [<base>]"
|
|
warn ""
|
|
exit 0
|
|
fi
|
|
|
|
current_branch=$(git_current_branch)
|
|
|
|
# Determine column width first
|
|
width=0
|
|
for branch in $release_branches; do
|
|
len=${#branch}
|
|
width=$(max $width $len)
|
|
done
|
|
width=$(($width+3-${#PREFIX}))
|
|
|
|
for branch in $release_branches; do
|
|
base=$(git merge-base "$branch" "$DEVELOP_BRANCH")
|
|
develop_sha=$(git rev-parse "$DEVELOP_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" = "$develop_sha" ]; then
|
|
printf "(no commits yet)"
|
|
else
|
|
nicename=$(git rev-parse --short "$base")
|
|
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_release_branches() {
|
|
local release_branches first_branch
|
|
|
|
release_branches=$(git_local_branches_prefixed "$PREFIX")
|
|
first_branch=$(echo ${release_branches} | head -n1)
|
|
|
|
first_branch=${first_branch#$PREFIX}
|
|
[ -z "$release_branches" ] || die "There is an existing release branch '$first_branch'. Finish that one first."
|
|
}
|
|
|
|
cmd_start() {
|
|
OPTIONS_SPEC="\
|
|
git flow release start [options] <version> [<base>]
|
|
|
|
Start a new release branch
|
|
--
|
|
h,help! Show this help
|
|
showcommands! Show git commands while executing them
|
|
F,[no]fetch Fetch from $ORIGIN before performing finish
|
|
v,verbose! Verbose (more) output
|
|
"
|
|
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 "release.start.fetch" "fetch"
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
eval set -- "${FLAGS_ARGV}"
|
|
base=${2:-$DEVELOP_BRANCH}
|
|
|
|
# Run filter on the version
|
|
VERSION=$(run_filter_hook release-start-version $VERSION)
|
|
if [ $? -eq 127 ]; then
|
|
die $VERSION
|
|
fi
|
|
|
|
# As VERSION might have changed reset BRANCH with new VERSION
|
|
BRANCH=$PREFIX$VERSION
|
|
|
|
require_base_is_local_branch "$base"
|
|
gitflow_require_version_arg
|
|
|
|
require_no_existing_release_branches
|
|
|
|
# Sanity checks
|
|
git_config_bool_exists "gitflow.allowdirty" || require_clean_working_tree
|
|
require_branch_absent "$BRANCH"
|
|
require_tag_absent "$VERSION_PREFIX$VERSION"
|
|
if flag fetch; then
|
|
git_fetch_branch "$ORIGIN" "$base"
|
|
fi
|
|
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 release 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 "- Bump the version number now!"
|
|
echo "- Start committing last-minute fixes in preparing your release"
|
|
echo "- When done, run:"
|
|
echo
|
|
echo " git flow release finish '$VERSION'"
|
|
echo
|
|
}
|
|
|
|
cmd_finish() {
|
|
OPTIONS_SPEC="\
|
|
git flow release finish [-h] [-F] [-s] [-u] [-m | -f] [-p] [-k] [-n] [-b] [-S] <version>
|
|
|
|
|
|
Finish a release branch
|
|
--
|
|
h,help Show this help
|
|
showcommands! Show git commands while executing them
|
|
F,[no]fetch Fetch from origin before performing finish
|
|
s,sign! Sign the release tag cryptographically
|
|
u,signingkey! Use the given GPG-key for the digital signature (implies -s)
|
|
m,message! Use the given tag message
|
|
f,[no]messagefile= Use the contents of the given file as a tag message
|
|
p,[no]push Push to origin after performing finish
|
|
[no]pushproduction Push the production branch
|
|
[no]pushdevelop Push the develop branch
|
|
[no]pushtag Push the tag
|
|
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 release branch after finish
|
|
n,[no]tag Don't tag this release
|
|
b,[no]nobackmerge Don't back-merge master, or tag if applicable, in develop
|
|
S,[no]squash Squash release during merge
|
|
[no]ff-master Fast forward master branch if possible
|
|
T,tagname! Use given tag name
|
|
nodevelopmerge! Don't back-merge develop branch
|
|
"
|
|
# 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 a tag message" f
|
|
DEFINE_boolean 'push' false "push to $ORIGIN after performing finish" p
|
|
DEFINE_boolean 'pushproduction' false "push the production branch"
|
|
DEFINE_boolean 'pushdevelop' false "push the develop branch"
|
|
DEFINE_boolean 'pushtag' false "push the tag"
|
|
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 release branch after finish" D
|
|
DEFINE_boolean 'notag' false "don't tag this release" 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_boolean 'ff-master' false "fast forward master branch if possible"
|
|
DEFINE_string 'tagname' "" "use the given tag name" T
|
|
DEFINE_boolean 'nodevelopmerge' false "don't merge $BRANCH into $DEVELOP_BRANCH "
|
|
|
|
# Override defaults with values from config
|
|
gitflow_override_flag_boolean "release.finish.fetch" "fetch"
|
|
gitflow_override_flag_boolean "release.finish.sign" "sign"
|
|
gitflow_override_flag_boolean "release.finish.push" "push"
|
|
gitflow_override_flag_boolean "release.finish.pushproduction" "pushproduction"
|
|
gitflow_override_flag_boolean "release.finish.pushdevelop" "pushdevelop"
|
|
gitflow_override_flag_boolean "release.finish.pushtag" "pushtag"
|
|
gitflow_override_flag_boolean "release.finish.keep" "keep"
|
|
gitflow_override_flag_boolean "release.finish.keepremote" "keepremote"
|
|
gitflow_override_flag_boolean "release.finish.keeplocal" "keeplocal"
|
|
gitflow_override_flag_boolean "release.finish.force-delete" "force_delete"
|
|
gitflow_override_flag_boolean "release.finish.notag" "notag"
|
|
gitflow_override_flag_boolean "release.finish.nobackmerge" "nobackmerge"
|
|
gitflow_override_flag_boolean "release.finish.squash" "squash"
|
|
gitflow_override_flag_boolean "release.finish.squash-info" "squash_info"
|
|
gitflow_override_flag_boolean "release.finish.ff-master" "ff-master"
|
|
gitflow_override_flag_string "release.finish.signingkey" "signingkey"
|
|
gitflow_override_flag_string "release.finish.message" "message"
|
|
gitflow_override_flag_string "release.finish.messagefile" "messagefile"
|
|
gitflow_override_flag_boolean "release.finish.nodevelopmerge" "nodevelopmerge"
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
# Use current branch if no version is given
|
|
if [ "$VERSION" = "" ]; then
|
|
gitflow_use_current_branch_version
|
|
fi
|
|
|
|
|
|
# Run filter on the version
|
|
VERSION=$(run_filter_hook release-finish-version $VERSION)
|
|
if [ $? -eq 127 ]; then
|
|
die $VERSION
|
|
fi
|
|
|
|
# Use branch name if no tag name is given
|
|
if [ "$FLAGS_tagname" != "" ]; then
|
|
TAGNAME=$FLAGS_tagname
|
|
else
|
|
TAGNAME=$VERSION
|
|
fi
|
|
|
|
# As VERSION might have changed reset BRANCH with new VERSION
|
|
BRANCH=$PREFIX$VERSION
|
|
|
|
BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
|
|
BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_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 release branch '$BRANCH'."
|
|
|
|
# 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
|
|
|
|
# Pushing implies we push all.
|
|
if flag push; then
|
|
FLAGS_pushproduction=$FLAGS_TRUE
|
|
FLAGS_pushdevelop=$FLAGS_TRUE
|
|
FLAGS_pushtag=$FLAGS_TRUE
|
|
fi
|
|
# If we push either of these it means we need to do a push
|
|
if flag pushproduction || flag pushdevelop || flag pushtag; then
|
|
FLAGS_push=$FLAGS_TRUE
|
|
fi
|
|
|
|
# Sanity checks
|
|
require_branch "$BRANCH"
|
|
require_clean_working_tree
|
|
|
|
# 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
|
|
|
|
if [ "$BASE_BRANCH" = "$DEVELOP_BRANCH" ]; then
|
|
_finish_from_develop
|
|
else
|
|
_finish_base
|
|
fi
|
|
}
|
|
|
|
cmd_branch() {
|
|
OPTIONS_SPEC="\
|
|
git flow release branch [-h] [-F] [-s] [-u] [-m] [-f] [-p] [-n] [-S] <version> [<name>]
|
|
|
|
|
|
Release a branch [<name>], if a name is not given it defaults to the develop branch, and use the given version <version>
|
|
--
|
|
h,help Show this help
|
|
showcommands! Show git commands while executing them
|
|
F,[no]fetch Fetch from origin before performing finish
|
|
s,sign! Sign the release tag cryptographically
|
|
u,signingkey! Use the given GPG-key for the digital signature (implies -s)
|
|
m,message! Use the given tag message
|
|
f,[no]messagefile= Use the contents of the given file as a tag message
|
|
p,[no]push Push to origin after performing finish
|
|
n,[no]tag Don't tag this release
|
|
S,[no]squash Squash release during merge
|
|
"
|
|
local opts
|
|
|
|
# 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 a tag message" f
|
|
DEFINE_boolean 'push' false "push to $ORIGIN after performing finish" p
|
|
DEFINE_boolean 'notag' false "don't tag this release" n
|
|
DEFINE_boolean 'squash' false "squash release during merge" S
|
|
DEFINE_boolean 'squash-info' false "add branch info during squash"
|
|
|
|
# Override defaults with values from config
|
|
gitflow_override_flag_boolean "release.branch.fetch" "fetch"
|
|
gitflow_override_flag_boolean "release.branch.sign" "sign"
|
|
gitflow_override_flag_boolean "release.branch.push" "push"
|
|
gitflow_override_flag_boolean "release.branch.notag" "notag"
|
|
gitflow_override_flag_boolean "release.branch.squash" "squash"
|
|
gitflow_override_flag_boolean "release.branch.squash-info" "squash_info"
|
|
gitflow_override_flag_string "release.branch.signingkey" "signingkey"
|
|
gitflow_override_flag_string "release.branch.message" "message"
|
|
gitflow_override_flag_string "release.branch.messagefile" "messagefile"
|
|
|
|
# Parse arguments
|
|
FLAGS "$@" || exit $?
|
|
eval set -- "${FLAGS_ARGV}"
|
|
|
|
# Read arguments into global variables
|
|
VERSION=$1
|
|
BRANCH=${2:-$DEVELOP_BRANCH}
|
|
|
|
# Run filter on the version
|
|
VERSION=$(run_filter_hook branch-finish-version $VERSION)
|
|
if [ $? -eq 127 ]; then
|
|
die $VERSION
|
|
fi
|
|
|
|
gitflow_require_version_arg
|
|
|
|
# Handle flags that imply other flags
|
|
if [ "$FLAGS_signingkey" != "" ]; then
|
|
FLAGS_sign=$FLAGS_TRUE
|
|
fi
|
|
|
|
# Sanity checks
|
|
if gitflow_is_prefixed_branch "$BRANCH"; then
|
|
die "Branch '$BRANCH' seems to be a git-flow branch. It's not allowed to release this directly."
|
|
fi
|
|
|
|
if [ "$BRANCH" = "$MASTER_BRANCH" ]; then
|
|
die "Can not release from the the master branch"
|
|
fi
|
|
|
|
require_branch "$BRANCH"
|
|
require_clean_working_tree
|
|
|
|
# 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" "$MASTER_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/$MASTER_BRANCH"; then
|
|
require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
|
|
fi
|
|
|
|
run_pre_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
# 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 ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then
|
|
git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_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 release branch '$BRANCH'" "$MASTER_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$VERSION"; 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 release-branch-tag-message "${FLAGS_message}" "$VERSION_PREFIX$VERSION")
|
|
opts="$opts -m '$FLAGS_message'"
|
|
fi
|
|
[ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'"
|
|
eval git_do tag $opts "$VERSION_PREFIX$VERSION" || die "Tagging failed. Please run finish again to retry."
|
|
fi
|
|
fi
|
|
|
|
run_post_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
if flag push; then
|
|
git_do push "$ORIGIN" "$MASTER_BRANCH" || die "Could not push branch '$MASTER_BRANCH' to remote '$ORIGIN'."
|
|
if noflag notag; then
|
|
git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'."
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
echo "Summary of actions:"
|
|
if flag fetch; then
|
|
echo "- Latest objects have been fetched from '$ORIGIN'"
|
|
fi
|
|
echo "- Branch '$BRANCH' has been merged into '$MASTER_BRANCH'"
|
|
if noflag notag; then
|
|
echo "- The release was tagged '$VERSION_PREFIX$VERSION'"
|
|
fi
|
|
|
|
if flag push; then
|
|
echo "- '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'"
|
|
fi
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
}
|
|
|
|
cmd_publish() {
|
|
OPTIONS_SPEC="\
|
|
git flow release publish [-h] <name>
|
|
|
|
Publish the release branch <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" "$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" "$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_track() {
|
|
OPTIONS_SPEC="\
|
|
git flow release track [-h] <name>
|
|
|
|
Start tracking release <name> that is shared on $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_local_branch_absent "$BRANCH"
|
|
|
|
run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
git_do fetch -q "$ORIGIN" || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'."
|
|
git_remote_branch_exists "$ORIGIN/$BRANCH"
|
|
|
|
# Create tracking branch
|
|
git_do checkout -b "$BRANCH" "$ORIGIN/$BRANCH" || die "Could not create branch '$BRANCH'."
|
|
|
|
run_post_hook "$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
echo
|
|
echo "Summary of actions:"
|
|
echo "- A new remote tracking branch '$BRANCH' was created"
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
}
|
|
|
|
cmd_rebase() {
|
|
OPTIONS_SPEC="\
|
|
git flow release 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 "release.rebase.interactive" "interactive"
|
|
gitflow_override_flag_boolean "release.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 release 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_delete() {
|
|
OPTIONS_SPEC="\
|
|
git flow release delete [-h] [-f] [-r] <name>
|
|
|
|
Delete the given release 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 "release.delete.fetch" "fetch"
|
|
gitflow_override_flag_boolean "release.delete.remote" "remote"
|
|
|
|
# Parse arguments
|
|
parse_args "$@"
|
|
|
|
gitflow_require_version_arg
|
|
|
|
# Sanity checks
|
|
require_branch "$BRANCH"
|
|
|
|
BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
|
|
BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH}
|
|
|
|
run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH"
|
|
|
|
current_branch=$(git_current_branch)
|
|
# We can't delete a branch we are on, switch to the develop branch.
|
|
if [ "$BRANCH" = "$current_branch" ]; then
|
|
require_clean_working_tree
|
|
if git_local_branch_exists "$BASE_BRANCH"; then
|
|
git_do checkout "$BASE_BRANCH"
|
|
else
|
|
git_do checkout "$DEVELOP_BRANCH" || die "Could not check out branch '$DEVELOP_BRANCH'."
|
|
fi
|
|
fi
|
|
|
|
if ( git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH" && git_is_branch_merged_into "$BRANCH" "$BASE_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 "Release branch '$BRANCH' has been not been merged in branch '$MASTER_BRANCH' and/or branch '$BASE_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 "- Release branch '$BRANCH' has been deleted."
|
|
flag remote && echo "- Release branch '$BRANCH' in '$ORIGIN' has been deleted."
|
|
echo "- You are now on branch '$(git_current_branch)'"
|
|
echo
|
|
}
|