Commit d93075cd authored by Clive Makamara's avatar Clive Makamara

nexe build

parent bf9c3d30
node_modules/* node_modules/*
npm-debug.log npm-debug.log
npm-debug.log* npm-debug.log*
\ No newline at end of file build/*
\ No newline at end of file
#
# Authors:
# Copyright 2012-2016 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.
#
prefix=/usr/local
datarootdir=$(prefix)/share
docdir=$(datarootdir)/doc/gitflow
# files that need mode 755
EXEC_FILES=git-flow
# files that need mode 644
SCRIPT_FILES =git-flow-init
SCRIPT_FILES+=git-flow-feature
SCRIPT_FILES+=git-flow-bugfix
SCRIPT_FILES+=git-flow-hotfix
SCRIPT_FILES+=git-flow-release
SCRIPT_FILES+=git-flow-support
SCRIPT_FILES+=git-flow-version
SCRIPT_FILES+=git-flow-log
SCRIPT_FILES+=git-flow-config
SCRIPT_FILES+=gitflow-common
SCRIPT_FILES+=gitflow-shFlags
# Hook files
HOOK_FILES=$(wildcard hooks/*)
all:
@echo "usage: make install"
@echo " make uninstall"
install:
install -d -m 0755 $(prefix)/bin
install -d -m 0755 $(docdir)/hooks
install -m 0755 $(EXEC_FILES) $(prefix)/bin
install -m 0644 $(SCRIPT_FILES) $(prefix)/bin
install -m 0644 $(HOOK_FILES) $(docdir)/hooks
uninstall:
test -d $(prefix)/bin && \
cd $(prefix)/bin && \
rm -f $(EXEC_FILES) $(SCRIPT_FILES)
test -d $(docdir) && \
rm -rf $(docdir)
#!/bin/bash
# git-flow make-less installer for *nix systems, by Rick Osborne
# Based on the git-flow core Makefile:
# http://github.com/dreidev/gitflow/blob/master/Makefile
# Licensed under the same restrictions as git-flow:
# http://github.com/dreidev/gitflow/blob/develop/LICENSE
# Updated for the fork at petervanderdoes
usage() {
echo "Usage: [environment] gitflow-installer.sh [install|uninstall] [stable|develop]"
echo "Environment:"
echo " PREFIX=$PREFIX"
echo " REPO_HOME=$REPO_HOME"
echo " REPO_NAME=$REPO_NAME"
exit 1
}
# Does this need to be smarter for each host OS?
if [ -z "$PREFIX" ] ; then
PREFIX="/usr/local"
fi
if [ -z "$REPO_NAME" ] ; then
REPO_NAME="gitflow"
fi
if [ -z "$REPO_HOME" ] ; then
REPO_HOME="https://github.com/dreidev/gitflow.git"
fi
EXEC_PREFIX="$PREFIX"
BINDIR="$EXEC_PREFIX/bin"
DATAROOTDIR="$PREFIX/share"
DOCDIR="$DATAROOTDIR/doc/gitflow"
EXEC_FILES="git-flow"
SCRIPT_FILES="git-flow-init git-flow-feature git-flow-bugfix git-flow-hotfix git-flow-release git-flow-support git-flow-version gitflow-common gitflow-shFlags git-flow-config"
HOOK_FILES="$REPO_NAME/hooks/*"
echo "### git-flow no-make installer ###"
case "$1" in
uninstall)
echo "Uninstalling git-flow from $PREFIX"
if [ -d "$BINDIR" ] ; then
for script_file in $SCRIPT_FILES $EXEC_FILES ; do
echo "rm -vf $BINDIR/$script_file"
rm -vf "$BINDIR/$script_file"
done
rm -rf "$DOCDIR"
else
echo "The '$BINDIR' directory was not found."
fi
exit
;;
help)
usage
exit
;;
install)
if [ -z $2 ]; then
usage
exit
fi
echo "Installing git-flow to $BINDIR"
if [ -d "$REPO_NAME" -a -d "$REPO_NAME/.git" ] ; then
echo "Using existing repo: $REPO_NAME"
else
echo "Cloning repo from GitHub to $REPO_NAME"
git clone "$REPO_HOME" "$REPO_NAME"
fi
cd "$REPO_NAME"
git pull
cd "$OLDPWD"
case "$2" in
stable)
cd "$REPO_NAME"
git checkout master
cd "$OLDPWD"
;;
develop)
cd "$REPO_NAME"
git checkout develop
cd "$OLDPWD"
;;
*)
usage
exit
;;
esac
install -v -d -m 0755 "$PREFIX/bin"
install -v -d -m 0755 "$DOCDIR/hooks"
for exec_file in $EXEC_FILES ; do
install -v -m 0755 "$REPO_NAME/$exec_file" "$BINDIR"
done
for script_file in $SCRIPT_FILES ; do
install -v -m 0644 "$REPO_NAME/$script_file" "$BINDIR"
done
for hook_file in $HOOK_FILES ; do
install -v -m 0644 "$hook_file" "$DOCDIR/hooks"
done
exit
;;
*)
usage
exit
;;
esac
@echo off
setlocal
if not "%~1"=="" set GIT_HOME=%~f1
if "%GIT_HOME%"=="" call :FindGitHome "git.cmd"
if exist "%GIT_HOME%" goto :GitHomeOK
echo MsysGit installation directory not found.>&2
echo Try to give the directory name on the command line:>&2
echo %0 "%ProgramFiles%\Git"
endlocal
exit /B 1
:GitHomeOK
set ERR=0
echo Installing gitflow into "%GIT_HOME%"...
call :ChkGetopt getopt.exe || set ERR=1
if %ERR%==1 goto :End
echo getopt.exe... Found
if not exist "%GIT_HOME%\bin\git-flow" goto :Install
echo GitFlow is already installed.>&2
set /p mychoice="Do you want to replace it [y/n]"
if "%mychoice%"=="y" goto :DeleteOldFiles
goto :Abort
:DeleteOldFiles
echo Deleting old files...
for /F %%i in ("%GIT_HOME%\git-flow*" "%GIT_HOME%\gitflow-*") do if exist "%%~fi" del /F /Q "%%~fi"
:Install
echo Copying files...
::goto :EOF
xcopy "%~dp0\..\git-flow" "%GIT_HOME%\bin" /Y /R /F
if errorlevel 4 if not errorlevel 5 goto :AccessDenied
if errorlevel 1 set ERR=1
xcopy "%~dp0\..\git-flow*" "%GIT_HOME%\bin" /Y /R /F || set ERR=1
xcopy "%~dp0\..\gitflow-*" "%GIT_HOME%\bin" /Y /R /F || set ERR=1
if %ERR%==1 choice /T 30 /C Y /D Y /M "Some unexpected errors happened. Sorry, you'll have to fix them by yourself."
:End
endlocal & exit /B %ERR%
goto :EOF
:AccessDenied
set ERR=1
echo.
echo You should run this script with "Full Administrator" rights:>&2
echo - Right-click with Shift on the script from the Explorer>&2
echo - Select "Run as administrator">&2
choice /T 30 /C YN /D Y /N >nul
goto :End
:Abort
echo Installation canceled.>&2
set ERR=1
goto :End
:ChkGetopt
:: %1 is getopt.exe
if exist "%GIT_HOME%\bin\%1" goto :EOF
if exist "%~f$PATH:1" goto :EOF
echo %GIT_HOME%\bin\%1 not found.>&2
echo You have to install this file manually. See the GitFlow README.
exit /B 1
:FindGitHome
setlocal
set GIT_CMD_DIR=%~dp$PATH:1
if "%GIT_CMD_DIR%"=="" endlocal & goto :EOF
endlocal & set GIT_HOME=%GIT_CMD_DIR:~0,-5%
goto :EOF
#!/bin/sh
#
# 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-2016 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.
#
#
# enable debug mode
if [ "$DEBUG" = "yes" ]; then
set -x
fi
# Setup the GITFLOW_DIR for different operating systems.
# This is mostly to make sure that we get the correct directory when the
# git-flow file is a symbolic link
case $(uname -s) in
Linux)
export GITFLOW_DIR=$(dirname "$(readlink -e "$0")")
;;
FreeBSD|OpenBSD|NetBSD)
export FLAGS_GETOPT_CMD='/usr/local/bin/getopt'
export GITFLOW_DIR=$(dirname "$(realpath "$0")")
;;
Darwin)
PRG="$0"
while [ -h "$PRG" ]; do
link=$(readlink "$PRG")
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="$(dirname "$PRG")/$link"
fi
done
export GITFLOW_DIR=$(dirname "$PRG")
;;
*MINGW*)
export GITFLOW_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
pwd () {
builtin pwd -W
}
;;
*)
# The sed expression here replaces all backslashes by forward slashes.
# This helps our Windows users, while not bothering our Unix users.)
export GITFLOW_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
;;
esac
# Extra environment settings
if [ -f ~/.gitflow_export ]; then
if grep -E 'GITFLOW_FLAG_(SHOWCOMMANDS|INIT|FEATURE|HOTFIX|RELEASE|SUPPORT)' ~/.gitflow_export > /dev/null; then
echo "Using environment variables for \"showcommands\", \"init\", \"feature\", \"hotfix\", \"release\" and \"support\" in ~/.gitflow_export has deprecated, use git config instead."
echo ""
exit 1;
else
. ~/.gitflow_export
fi
fi
usage() {
echo "usage: git flow <subcommand>"
echo
echo "Available subcommands are:"
echo " init Initialize a new git repo with support for the branching model."
echo " feature Manage your feature branches."
echo " bugfix Manage your bugfix branches."
echo " release Manage your release branches."
echo " hotfix Manage your hotfix branches."
echo " support Manage your support branches."
echo " version Shows version information."
echo " config Manage your git-flow configuration."
echo " log Show log deviating from base branch."
echo
echo "Try 'git flow <subcommand> help' for details."
}
main() {
if [ $# -lt 1 ]; then
usage
exit 1
fi
# Use the shFlags project to parse the command line arguments
. "$GITFLOW_DIR/gitflow-shFlags"
FLAGS_PARENT="git flow"
# Load common functionality
. "$GITFLOW_DIR/gitflow-common"
# allow user to request git action logging
DEFINE_boolean 'showcommands' false 'Show actions taken (git commands)'
# but if the user prefers that the logging is always on,
# use the environmental variables.
gitflow_override_flag_boolean 'showcommands' 'showcommands'
# Sanity checks
SUBCOMMAND="$1"; shift
if [ "${SUBCOMMAND}" = "finish" ] || [ "${SUBCOMMAND}" = "delete" ] || [ "${SUBCOMMAND}" = "publish" ] || [ "${SUBCOMMAND}" = "rebase" ]; then
_current_branch=$(git_current_branch)
if gitflow_is_prefixed_branch "${_current_branch}"; then
if startswith "${_current_branch}" $(git config --get gitflow.prefix.feature); then
SUBACTION="${SUBCOMMAND}"
SUBCOMMAND="feature"
_prefix=$(git config --get gitflow.prefix.feature)
_short_branch_name=$(echo ${_current_branch#*${_prefix}})
else
if startswith "${_current_branch}" $(git config --get gitflow.prefix.bugfix); then
SUBACTION="${SUBCOMMAND}"
SUBCOMMAND="bugfix"
_prefix=$(git config --get gitflow.prefix.bugfix)
_short_branch_name=$(echo ${_current_branch#*${_prefix}})
else
if startswith "${_current_branch}" $(git config --get gitflow.prefix.hotfix); then
SUBACTION="${SUBCOMMAND}"
SUBCOMMAND="hotfix"
_prefix=$(git config --get gitflow.prefix.hotfix)
_short_branch_name=$(echo ${_current_branch#*${_prefix}})
else
if startswith "${_current_branch}" $(git config --get gitflow.prefix.release); then
SUBACTION="${SUBCOMMAND}"
SUBCOMMAND="release"
_prefix=$(git config --get gitflow.prefix.release)
_short_branch_name=$(echo ${_current_branch#*${_prefix}})
fi
fi
fi
fi
fi
fi
if [ ! -e "$GITFLOW_DIR/git-flow-$SUBCOMMAND" ]; then
usage
exit 1
fi
# Run command
. "$GITFLOW_DIR/git-flow-$SUBCOMMAND"
FLAGS_PARENT="git flow $SUBCOMMAND"
if [ -z "${SUBACTION}" ]; then
# If the first argument is a flag, it starts with '-', we interpret this
# argument as a flag for the default command.
if startswith "$1" "-"; then
SUBACTION="default"
elif [ -z "$1" ]; then
SUBACTION="default"
else
SUBACTION="$1"
shift
# Do not allow direct calls to subactions with an underscore.
if $(contains "$SUBACTION" "_"); then
warn "Unknown subcommand: '$SUBACTION'"
usage
exit 1
fi
# Replace the dash with an underscore as bash doesn't allow a dash
# in the function name.
SUBACTION=$(echo "$SUBACTION" |tr '-' '_')
fi
fi
if ! type "cmd_$SUBACTION" >/dev/null 2>&1; then
warn "Unknown subcommand: '$SUBACTION'"
usage
exit 1
fi
# Run the specified action
if [ $SUBACTION != "help" ] && [ $SUBCOMMAND != "init" ]; then
initialize
fi
if [ $SUBACTION != 'default' ]; then
FLAGS_PARENT="git flow $SUBCOMMAND $SUBACTION"
fi
cmd_$SUBACTION "$@" "${_short_branch_name}"
}
main "$@"
#
# 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-2016 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.bugfix >/dev/null 2>&1 || die "Bugfix prefix not set. Please run 'git flow init'."
gitflow_load_settings
PREFIX=$(git config --get gitflow.prefix.bugfix)
}
usage() {
OPTIONS_SPEC="\
git flow bugfix [list]
git flow bugfix start
git flow bugfix finish
git flow bugfix publish
git flow bugfix track
git flow bugfix diff
git flow bugfix rebase
git flow bugfix checkout
git flow bugfix pull
git flow bugfix delete
Manage your bugfix branches.
For more specific help type the command followed by --help
--
"
flags_help
}
cmd_default() {
cmd_list "$@"
}
cmd_list() {
OPTIONS_SPEC="\
git flow bugfix [list] [-h] [-v]
Lists all the existing bugfix branches in the local repository.
--
h,help! Show this help
v,verbose Verbose (more) output
"
local bugfix_branches current_branch width branch len
local base develop_sha branch_sha
# Define flags
DEFINE_boolean 'verbose' false 'verbose (more) output' v
# Parse argun=ments
parse_args "$@"
bugfix_branches=$(git_local_branches_prefixed "$PREFIX")
if [ -z "$bugfix_branches" ]; then
warn "No bugfix branches exist."
warn ""
warn "You can start a new bugfix branch:"
warn ""
warn " git flow bugfix start <name> [<base>]"
warn ""
exit 0
fi
current_branch=$(git_current_branch)
# Determine column width first
width=0
for branch in $bugfix_branches; do
len=${#branch}
width=$(max $width $len)
done
width=$(($width+3-${#PREFIX}))
for branch in $bugfix_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)"
elif [ "$base" = "$branch_sha" ]; then
printf "(is behind develop, may ff)"
elif [ "$base" = "$develop_sha" ]; then
printf "(based on latest develop)"
else
printf "(may be rebased)"
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
NAME=''
else
NAME=$1
fi
BRANCH=$PREFIX$NAME
}
parse_remote_name() {
# Parse arguments
FLAGS "$@" || exit $?
eval set -- "${FLAGS_ARGV}"
# read arguments into global variables
if [ -z $1 ]; then
REMOTE=''
else
REMOTE=$1
fi
if [ -z $2 ]; then
NAME=''
else
NAME=$2
fi
BRANCH=$PREFIX$NAME
}
cmd_start() {
OPTIONS_SPEC="\
git flow bugfix start [-h] [-F] <name> [<base>]
Start new bugfix <name>, optionally basing it on <base> instead of <develop>
--
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 local operation' F
# Override defaults with values from config
gitflow_override_flag_boolean "bugfix.start.fetch" "fetch"
# Parse arguments
parse_args "$@"
eval set -- "${FLAGS_ARGV}"
base=${2:-$DEVELOP_BRANCH}
require_base_is_local_branch "$base"
gitflow_require_name_arg
gitflow_config_set_base_branch $base $BRANCH
# Update the local repo with remote changes, if asked
if flag fetch; then
git_fetch_branch "$ORIGIN" "$base"
fi
# Sanity checks
require_branch_absent "$BRANCH"
# If the origin branch counterpart exists, assert that the local branch
# isn't behind it (to avoid unnecessary rebasing)
if git_remote_branch_exists "$ORIGIN/$base"; then
require_branches_equal "$base" "$ORIGIN/$base"
fi
run_pre_hook "$NAME" "$ORIGIN" "$BRANCH" "$base"
# create branch
git_do checkout -b "$BRANCH" "$base" || die "Could not create bugfix branch '$BRANCH'."
run_post_hook "$NAME" "$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 "Now, start committing on your bugfix. When done, use:"
echo ""
echo " git flow bugfix finish $NAME"
echo
}
cmd_finish() {
OPTIONS_SPEC="\
git flow bugfix finish [-h] [-F] [-r] [-p] [-k] [-D] [-S] [--no-ff] <name|nameprefix>
Finish bugfix <name>
--
h,help! Show this help
showcommands! Show git commands while executing them
F,[no]fetch Fetch from origin before performing finish
r,[no]rebase Rebase before merging
p,[no]preserve-merges Preserve merges while rebasing
k,[no]keep Keep branch after performing finish
keepremote! Keep the remote branch
keeplocal! Keep the local branch
D,[no]force_delete Force delete bugfix branch after finish
S,[no]squash Squash bugfix during merge
no-ff! Never fast-forward during the merge
"
local finish_base
# Define flags
DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F
DEFINE_boolean 'rebase' false "rebase before merging" r
DEFINE_boolean 'preserve-merges' false 'try to recreate merges while rebasing' 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 bugfix branch after finish" D
DEFINE_boolean 'squash' false "squash bugfix during merge" S
DEFINE_boolean 'squash-info' false "add branch info during squash"
DEFINE_boolean 'no-ff!' false "Don't fast-forward ever during merge "
# Override defaults with values from config
gitflow_override_flag_boolean "bugfix.finish.fetch" "fetch"
gitflow_override_flag_boolean "bugfix.finish.rebase" "rebase"
gitflow_override_flag_boolean "bugfix.finish.preserve-merges" "preserve_merges"
gitflow_override_flag_boolean "bugfix.finish.keep" "keep"
gitflow_override_flag_boolean "bugfix.finish.keepremote" "keepremote"
gitflow_override_flag_boolean "bugfix.finish.keeplocal" "keeplocal"
gitflow_override_flag_boolean "bugfix.finish.force-delete" "force_delete"
gitflow_override_flag_boolean "bugfix.finish.squash" "squash"
gitflow_override_flag_boolean "bugfix.finish.squash-info" "squash_info"
gitflow_override_flag_boolean "bugfix.finish.no-ff" "no_ff"
# Parse arguments
parse_args "$@"
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
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"
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 bugfix branch '$BRANCH'."
# Detect if we're restoring from a merge conflict
if [ -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE" ]; then
#
# TODO: detect that we're working on the correct branch here!
# The user need not necessarily have given the same $NAME twice here
# (although he/she should).
#
# TODO: git_is_clean_working_tree() should provide an alternative
# exit code for "unmerged changes in working tree", which we should
# actually be testing for here
if git_is_clean_working_tree; then
finish_base=$(cat "$DOT_GIT_DIR/.gitflow/MERGE_BASE")
# Since the working tree is now clean, either the user did a
# successful merge manually, or the merge was cancelled.
# We detect this using git_is_branch_merged_into()
if git_is_branch_merged_into "$BRANCH" "$finish_base"; then
rm -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE"
helper_finish_cleanup
exit 0
else
# If the user cancelled the merge and decided to wait until
# later,that's fine. But we have to acknowledge this by
# removing the MERGE_BASE file and continuing normal execution
# of the finish
rm -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE"
fi
else
echo
echo "Merge conflicts not resolved yet, use:"
echo " git mergetool"
echo " git commit"
echo
echo "You can then complete the finish by running it again:"
echo " git flow bugfix finish $NAME"
echo
exit 1
fi
fi
# Sanity checks
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" "$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
run_pre_hook "$NAME" "$ORIGIN" "$BRANCH"
# If the user wants to rebase, do that first
if flag rebase; then
local _rebase_opts=""
if flag preserve_merges; then
_rebase_opts="$_rebase_opts -p"
fi
if flag showcommands; then
_rebase_opts="$_rebase_opts --showcommands"
fi
if ! git flow bugfix rebase $_rebase_opts "$NAME"; then
warn "Finish was aborted due to conflicts during rebase."
warn "Please finish the rebase manually now."
warn "When finished, re-run:"
warn " git flow bugfix finish '$NAME' '$BASE_BRANCH'"
exit 1
fi
fi
# Merge into BASE
git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'."
if noflag squash; then
if flag no_ff; then
git_do merge --no-ff "$BRANCH"
else
if [ "$(git rev-list -n2 "$BASE_BRANCH..$BRANCH" | wc -l)" -eq 1 ]; then
git_do merge --ff "$BRANCH"
else
git_do merge --no-ff "$BRANCH"
fi
fi
else
git_do merge --squash "$BRANCH"
flag squash_info && gitflow_create_squash_message "Merged bugfix branch '$BRANCH'" "$BASE_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG"
git_do commit
fi
if [ $? -ne 0 ]; then
# Oops.. we have a merge conflict!
# Write the given $BASE_BRANCH to a temporary file as we will
# be needing it later.
mkdir -p "$DOT_GIT_DIR/.gitflow"
echo "$BASE_BRANCH" > "$DOT_GIT_DIR/.gitflow/MERGE_BASE"
echo
echo "There were merge conflicts. To resolve the merge conflict manually, use:"
echo " git mergetool"
echo " git commit"
echo
echo "You can then complete the finish by running it again:"
echo " git flow bugfix finish $NAME"
echo
exit 1
fi
run_post_hook "$NAME" "$ORIGIN" "$BRANCH"
# When no merge conflict is detected, just clean up the bugfix branch
gitflow_config_remove_base_branch "$BRANCH"
helper_finish_cleanup
}
helper_finish_cleanup() {
local keepmsg remotebranchdeleted localbranchdeleted
# Sanity checks
require_branch "$BRANCH"
require_clean_working_tree
remotebranchdeleted=$FLAGS_FALSE
localbranchdeleted=$FLAGS_FALSE
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
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:"
echo "- The bugfix branch '$BRANCH' was merged into '$BASE_BRANCH'"
#echo "- Merge conflicts were resolved" # TODO: Add this line when it's supported
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 "- bugfix branch '$BRANCH' "$keepmsg
echo "- You are now on branch '$(git_current_branch)'"
echo
}
cmd_publish() {
OPTIONS_SPEC="\
git flow bugfix publish [-h] [<name>]
Publish bugfix branch <name> on $ORIGIN.
When <name> is omitted the current branch is used, but only if it's a bugfix branch.
--
h,help! Show this help
showcommands! Show git commands while executing them
"
# Parse arguments
parse_args "$@"
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
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 "$NAME" "$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 "$NAME" "$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 bugfix track [-h] <name>
Start tracking bugfix <name> that is shared on $ORIGIN
--
h,help! Show this help
showcommands! Show git commands while executing them
"
# Parse arguments
parse_args "$@"
gitflow_require_name_arg
# Sanity checks
require_clean_working_tree
require_local_branch_absent "$BRANCH"
run_pre_hook "$NAME" "$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'."
run_post_hook "$NAME" "$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_diff() {
OPTIONS_SPEC="\
git flow bugfix diff [-h] [<name|nameprefix>]
Show all changes in <name> that are not in the base
--
h,help! Show this help
showcommands! Show git commands while executing them
"
local base
# Parse arguments
parse_args "$@"
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
fi
base=$(gitflow_config_get_base_branch $BRANCH)
base=${base:-$DEVELOP_BRANCH}
git_do diff "$base..$BRANCH"
}
cmd_checkout() {
OPTIONS_SPEC="\
git flow bugfix checkout [-h] [<name|nameprefix>]
Switch to bugfix branch <name>
--
h,help! Show this help
showcommands! Show git commands while executing them
"
# Parse arguments
parse_args "$@"
NAME=$(gitflow_resolve_nameprefix "$NAME" "$PREFIX")
if [ $? -eq 0 ]; then
BRANCH=$PREFIX$NAME
git_do checkout "$BRANCH" || die "Could not check out branch '$BRANCH'."
fi
}
cmd_co() {
# Alias for checkout
cmd_checkout "$@"
}
cmd_rebase() {
OPTIONS_SPEC="\
git flow bugfix 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 "bugfix.rebase.interactive" "interactive"
gitflow_override_flag_boolean "bugfix.rebase.preserve-merges" "preserve_merges"
# Parse arguments
parse_args "$@"
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
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'..."
require_clean_working_tree
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 bugfix 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"
}
avoid_accidental_cross_branch_action() {
local current_branch
current_branch=$(git_current_branch)
if [ "$BRANCH" != "$current_branch" ]; then
warn "Trying to pull from '$BRANCH' while currently on branch '$current_branch'."
warn "To avoid unintended merges, git-flow aborted."
return 1
fi
return 0
}
cmd_pull() {
OPTIONS_SPEC="\
git flow bugfix pull [-h] <remote> [<name>]
Pull bugfix <name> from <remote>
--
h,help! Show this help
showcommands! Show git commands while executing them
"
local current_branch
# Define flags
DEFINE_boolean 'rebase' false "pull with rebase" r
warn "The command 'git flow bugfix pull' will be deprecated per version 2.0.0. Use 'git flow bugfix track' instead."
# Parse arguments
parse_remote_name "$@"
if [ -z "$REMOTE" ]; then
die "Name a remote explicitly."
fi
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
fi
# To avoid accidentally merging different bugfix branches into each other,
# die if the current bugfix branch differs from the requested $NAME
# argument.
current_branch=$(git_current_branch)
if startswith "$current_branch" "$PREFIX"; then
# We are on a local bugfix branch already, so $BRANCH must be equal to
# the current branch
avoid_accidental_cross_branch_action || die
fi
require_clean_working_tree
run_pre_hook "$NAME" "$REMOTE" "$BRANCH"
if git_local_branch_exists "$BRANCH"; then
# Again, avoid accidental merges
avoid_accidental_cross_branch_action || die
# We already have a local branch called like this, so simply pull the
# remote changes in
if flag rebase; then
if ! git_do pull --rebase -q "$REMOTE" "$BRANCH"; then
warn "Pull was aborted. There might be conflicts during rebase or '$REMOTE' might be inaccessible."
exit 1
fi
else
git_do pull -q "$REMOTE" "$BRANCH" || die "Failed to pull from remote '$REMOTE'."
fi
echo "Pulled $REMOTE's changes into $BRANCH."
else
# Setup the local branch clone for the first time
git_do fetch -q "$REMOTE" "$BRANCH" || die "Could not fetch branch '$BRANCH' from remote '$REMOTE'." # Stores in FETCH_HEAD
git_do branch --no-track "$BRANCH" FETCH_HEAD || die "Branch failed."
git_do checkout -q "$BRANCH" || die "Could not check out branch '$BRANCH'."
echo "Created local branch $BRANCH based on $REMOTE's $BRANCH."
fi
run_post_hook "$NAME" "$REMOTE" "$BRANCH"
}
cmd_delete() {
OPTIONS_SPEC="\
git flow bugfix delete [-h] [-f] [-r] <name>
Delete a given bugfix 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 "bugfix.delete.force" "force"
gitflow_override_flag_boolean "bugfix.delete.remote" "remote"
# Parse arguments
parse_args "$@"
gitflow_require_name_arg
# Sanity checks
require_branch "$BRANCH"
BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH}
run_pre_hook "$NAME" "$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" "$BASE_BRANCH"; then
git_do branch -d "$BRANCH" || die "Could not delete the $BRANCH."
if flag remote; then
git_do push "$ORIGIN" :"$BRANCH" || die "Could not delete the remote $BRANCH in $ORIGIN."
fi
else
if flag force; then
git_do branch -D "$BRANCH" || die "Could not delete the $BRANCH."
if flag remote; then
git_do push "$ORIGIN" :"$BRANCH" || die "Could not delete the remote $BRANCH in $ORIGIN."
fi
else
die "bugfix branch '$BRANCH' has been not been merged yet. Use -f to force the deletion."
fi
fi
gitflow_config_remove_base_section "$BRANCH"
run_post_hook "$NAME" "$ORIGIN" "$BRANCH"
echo
echo "Summary of actions:"
echo "- bugfix branch '$BRANCH' has been deleted."
flag remote && echo "- bugfix branch '$BRANCH' in '$ORIGIN' has been deleted."
echo "- You are now on branch '$(git_current_branch)'"
echo
}
#
# 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-2016 Peter van der Does. 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
gitflow_load_settings
}
usage() {
OPTIONS_SPEC="\
git flow config [list]
git flow config set
git flow config base
Manage the git-flow configuration.
For more specific help type the command followed by --help
--
"
flags_help
}
parse_args() {
# Parse options
FLAGS "$@" || exit $?
eval set -- "${FLAGS_ARGV}"
OPTION=$(echo $1|tr '[:upper:]' '[:lower:]')
if [ "$FLAGS_file" != "" ]; then
gitflow_config_option="--file '$FLAGS_file'"
elif flag local; then
gitflow_config_option="--local"
elif flag global; then
gitflow_config_option="--global"
elif flag system; then
gitflow_config_option="--system"
else
gitflow_config_option=""
fi
}
# Default entry when no SUBACTION is given
cmd_default() {
cmd_list "$@"
}
cmd_list() {
OPTIONS_SPEC="\
git flow config [list]
Show the git-flow configurations
--
h,help! Show this help
Use config file location
local! Use repository config file
global! Use global config file
system! Use system config file
file= Use given config file
"
local output
# Define flags
DEFINE_boolean 'local' false 'use repository config file'
DEFINE_boolean 'global' false 'use global config file'
DEFINE_boolean 'system' false 'use system config file'
DEFINE_string 'file' "" 'use given config file'
# Parse arguments
parse_args "$@"
output=$(git config $gitflow_config_option --get gitflow.branch.master)
echo "Branch name for production releases: $output "
output=$(git config $gitflow_config_option --get gitflow.branch.develop)
echo "Branch name for \"next release\" development: $output "
output=$(git config $gitflow_config_option --get gitflow.prefix.feature)
echo "Feature branch prefix: $output "
output=$(git config $gitflow_config_option --get gitflow.prefix.bugfix)
echo "Bugfix branch prefix: $output "
output=$(git config $gitflow_config_option --get gitflow.prefix.release)
echo "Release branch prefix: $output "
output=$(git config $gitflow_config_option --get gitflow.prefix.hotfix)
echo "Hotfix branch prefix: $output "
output=$(git config $gitflow_config_option --get gitflow.prefix.support)
echo "Support branch prefix: $output "
output=$(git config $gitflow_config_option --get gitflow.prefix.versiontag)
echo "Version tag prefix: $output "
}
cmd_set() {
OPTIONS_SPEC="\
git flow config set <option> <value>
Set the git-flow configuration option to the given value
--
h,help! Show this help
local! Use repository config file
global! Use global config file
system! Use system config file
file= Use given config file
"
local value cfg_option txt
# Define flags
DEFINE_boolean 'local' false 'use repository config file'
DEFINE_boolean 'global' false 'use global config file'
DEFINE_boolean 'system' false 'use system config file'
DEFINE_string 'file' "" 'use given config file'
# Parse arguments
parse_args "$@"
eval set -- "${FLAGS_ARGV}"
value=$2
case $OPTION in
master)
cfg_option="gitflow.branch.master"
txt="Branch name for production releases"
;;
develop)
cfg_option="gitflow.branch.develop"
txt="Branch name for \"next release\" development"
;;
feature)
cfg_option="gitflow.prefix.feature"
txt="Feature branch prefix"
;;
bugfix)
cfg_option="gitflow.prefix.bugfix"
txt="Bugfix branch prefix"
;;
hotfix)
cfg_option="gitflow.prefix.hotfix"
txt="Hotfix branch prefix"
;;
release)
cfg_option="gitflow.prefix.release"
txt="Release branch prefix"
;;
support)
cfg_option="gitflow.prefix.support"
txt="Support branch prefix"
;;
versiontagprefix)
cfg_option="gitflow.prefix.versiontag"
txt="Version tag prefix"
;;
allowmultihotfix)
cfg_option="gitflow.multi-hotfix"
txt="Allow multiple hotfix branches"
;;
*)
die_help "Invalid option given."
;;
esac
[ -n "$value" ] || die_help "No value given"
if [ $OPTION = "master" ]; then
develop_branch=$(git config --get gitflow.branch.develop)
if [ "$value" = $develop_branch ]; then
die "Production and \"next release\" branch should differ."
fi
if ! git_local_branch_exists "$value" && git_remote_branch_exists "origin/$value"; then
git_do branch "$value" "origin/$value" >/dev/null 2>&1
elif ! git_local_branch_exists "$value"; then
die "Local branch '$value' does not exist."
fi
fi
if [ $OPTION = "develop" ]; then
master_branch=$(git config --get gitflow.branch.master)
if [ "$value" = $master_branch ]; then
die "Production and \"next release\" branch should differ."
fi
if ! git_local_branch_exists "$value" && git_remote_branch_exists "origin/$value"; then
git_do branch "$value" "origin/$value" >/dev/null 2>&1
elif ! git_local_branch_exists "$value"; then
die "Local branch '$value' does not exist."
fi
fi
if [ $OPTION = "allowmultihotfix" ]; then
check_boolean "${value}"
case $? in
${FLAGS_ERROR})
die "Invalid value for option 'allowmultihotfix'. Valid values are 'true' or 'false'"
;;
*)
;;
esac
fi
git_do config $gitflow_config_option $cfg_option "$value"
case $? in
0)
;;
3)
die "The config file is invalid."
;;
4)
die "Can not write to the config file."
;;
*)
die "Unknown return code [$?]. Please file an issue about this error."
;;
esac
echo
echo "Summary of actions:"
if [ "$FLAGS_file" != "" ]; then
echo "- Using configuration file '$FLAGS_file'"
elif flag local; then
echo "- Using repository specific configuration file."
elif flag global; then
echo "- Using user-specific configuration file."
elif flag system; then
echo "- Using system-wide configuration file."
else
echo "- Using repository specific configuration file."
fi
echo "- $txt set to $value"
echo
}
cmd_base () {
OPTIONS_SPEC="\
git flow config base [<options>] <branch> [<base>]
Set the given <base> for the given <branch>
--
h,help! Show this help
get Get the base for the given branch (default behavior).
set Set the given base for the given branch.
"
DEFINE_boolean 'get' true 'Get the base for the given branch (default behavior).'
DEFINE_boolean 'set' false 'Set the given base for the given branch.'
FLAGS "$@" || exit $?
eval set -- "${FLAGS_ARGV}"
if flag 'set'; then
[ -z "$1" ] && die_help 'No branch given'
[ -z "$2" ] && die_help 'No base given'
__set_base "$@"
else
[ -z "$1" ] && die_help 'No branch given'
__get_base "$@"
fi
}
cmd_help() {
usage
exit 0
}
# Private functions
__set_base () {
require_branch "$1"
git_branch_exists "$2" || die_help "Given base doesn't exists or is not a branch."
gitflow_config_set_base_branch "$2" "$1"
}
__get_base () {
local base
base=$(gitflow_config_get_base_branch "$1")
echo
if [ -z "$base" ]; then
echo "Base branch not set for branch '"$1"'"
else
echo "Base branch for branch '"$1"' set to '"$base"'"
fi
}
#@IgnoreInspection BashAddShebang
#
# 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-2016 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.feature >/dev/null 2>&1 || die "Feature prefix not set. Please run 'git flow init'."
gitflow_load_settings
PREFIX=$(git config --get gitflow.prefix.feature)
}
usage() {
OPTIONS_SPEC="\
git flow feature [list]
git flow feature start
git flow feature finish
git flow feature pause
git flow feature interrupt
git flow feature resume
git flow feature review
git flow feature finish
git flow feature publish
git flow feature track
git flow feature diff
git flow feature rebase
git flow feature checkout
git flow feature pull
git flow feature delete
Manage your feature branches.
For more specific help type the command followed by --help
--
"
flags_help
}
cmd_default() {
cmd_list "$@"
}
cmd_list() {
OPTIONS_SPEC="\
git flow feature [list] [-h] [-v]
Lists all the existing feature branches in the local repository.
--
h,help! Show this help
v,verbose Verbose (more) output
"
local feature_branches current_branch width branch len
local base develop_sha branch_sha
# Define flags
DEFINE_boolean 'verbose' false 'verbose (more) output' v
# Parse argun=ments
parse_args "$@"
feature_branches=$(git_local_branches_prefixed "$PREFIX")
if [ -z "$feature_branches" ]; then
warn "No feature branches exist."
warn ""
warn "You can start a new feature branch:"
warn ""
warn " git flow feature start <name> [<base>]"
warn ""
exit 0
fi
current_branch=$(git_current_branch)
# Determine column width first
width=0
for branch in $feature_branches; do
len=${#branch}
width=$(max $width $len)
done
width=$(($width+3-${#PREFIX}))
for branch in $feature_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)"
elif [ "$base" = "$branch_sha" ]; then
printf "(is behind develop, may ff)"
elif [ "$base" = "$develop_sha" ]; then
printf "(based on latest develop)"
else
printf "(may be rebased)"
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
NAME=''
else
NAME=$1
fi
BRANCH=$PREFIX$NAME
}
parse_remote_name() {
# Parse arguments
FLAGS "$@" || exit $?
eval set -- "${FLAGS_ARGV}"
# read arguments into global variables
if [ -z $1 ]; then
REMOTE=''
else
REMOTE=$1
fi
if [ -z $2 ]; then
NAME=''
else
NAME=$2
fi
BRANCH=$PREFIX$NAME
}
cmd_start() {
OPTIONS_SPEC="\
git flow feature start [-h] [-F] <name> [<base>]
Start new feature <name>, optionally basing it on <base> instead of <develop>
--
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 local operation' F
# Override defaults with values from config
gitflow_override_flag_boolean "feature.start.fetch" "fetch"
# Parse arguments
parse_args "$@"
eval set -- "${FLAGS_ARGV}"
base=${2:-$DEVELOP_BRANCH}
require_base_is_local_branch "$base"
gitflow_require_name_arg
gitflow_config_set_base_branch $base $BRANCH
# Update the local repo with remote changes, if asked
if flag fetch; then
git_fetch_branch "$ORIGIN" "$base"
fi
# Sanity checks
require_branch_absent "$BRANCH"
# If the origin branch counterpart exists, assert that the local branch
# isn't behind it (to avoid unnecessary rebasing)
if git_remote_branch_exists "$ORIGIN/$base"; then
require_branches_equal "$base" "$ORIGIN/$base"
fi
run_pre_hook "$NAME" "$ORIGIN" "$BRANCH" "$base"
# create branch
git_do checkout -b "$BRANCH" "$base" || die "Could not create feature branch '$BRANCH'."
run_post_hook "$NAME" "$ORIGIN" "$BRANCH" "$base"
echo "How long do you think this feature will take in hours (e.g 1.5)?"
read TIME_REQUIRED
echo $TIME_REQUIRED >> "./.git/.gitflow/.timelog-feature-$NAME"
git add .
git commit --allow-empty -m "--Flow message(start) -- Started working on $BRANCH on $(date) estimated Time $TIME_REQUIRED hour(s)"
echo $(date +%s) >> "./.git/.gitflow/.timelog-feature-$NAME"
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 "Now, start committing on your feature. When done, use:"
echo ""
echo " git flow feature finish $NAME"
echo
}
cmd_finish() {
OPTIONS_SPEC="\
git flow feature finish [-h] [-F] [-r] [-p] [-k] [-D] [-S] [--no-ff] <name|nameprefix>
Finish feature <name>
--
h,help! Show this help
showcommands! Show git commands while executing them
F,[no]fetch Fetch from origin before performing finish
r,[no]rebase Rebase before merging
p,[no]preserve-merges Preserve merges while rebasing
[no]push Push to origin after performing finish
k,[no]keep Keep branch after performing finish
keepremote! Keep the remote branch
keeplocal! Keep the local branch
D,[no]force_delete Force delete feature branch after finish
S,[no]squash Squash feature during merge
no-ff! Never fast-forward during the merge
"
local finish_base
# Define flags
DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F
DEFINE_boolean 'rebase' false "rebase before merging" r
DEFINE_boolean 'preserve-merges' false 'try to recreate merges while rebasing' p
DEFINE_boolean 'push' false "push to $ORIGIN after performing finish"
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 feature branch after finish" D
DEFINE_boolean 'squash' false "squash feature during merge" S
DEFINE_boolean 'squash-info' false "add branch info during squash"
DEFINE_boolean 'no-ff!' false "Don't fast-forward ever during merge "
# Override defaults with values from config
gitflow_override_flag_boolean "feature.finish.fetch" "fetch"
gitflow_override_flag_boolean "feature.finish.rebase" "rebase"
gitflow_override_flag_boolean "feature.finish.preserve-merges" "preserve_merges"
gitflow_override_flag_boolean "feature.finish.push" "push"
gitflow_override_flag_boolean "feature.finish.keep" "keep"
gitflow_override_flag_boolean "feature.finish.keepremote" "keepremote"
gitflow_override_flag_boolean "feature.finish.keeplocal" "keeplocal"
gitflow_override_flag_boolean "feature.finish.force-delete" "force_delete"
gitflow_override_flag_boolean "feature.finish.squash" "squash"
gitflow_override_flag_boolean "feature.finish.squash-info" "squash_info"
gitflow_override_flag_boolean "feature.finish.no-ff" "no_ff"
# Parse arguments
parse_args "$@"
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
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"
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 feature branch '$BRANCH'."
# Detect if we're restoring from a merge conflict
if [ -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE" ]; then
#
# TODO: detect that we're working on the correct branch here!
# The user need not necessarily have given the same $NAME twice here
# (although he/she should).
#
# TODO: git_is_clean_working_tree() should provide an alternative
# exit code for "unmerged changes in working tree", which we should
# actually be testing for here
if git_is_clean_working_tree; then
finish_base=$(cat "$DOT_GIT_DIR/.gitflow/MERGE_BASE")
# Since the working tree is now clean, either the user did a
# successful merge manually, or the merge was cancelled.
# We detect this using git_is_branch_merged_into()
if git_is_branch_merged_into "$BRANCH" "$finish_base"; then
rm -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE"
helper_finish_cleanup
exit 0
else
# If the user cancelled the merge and decided to wait until
# later,that's fine. But we have to acknowledge this by
# removing the MERGE_BASE file and continuing normal execution
# of the finish
rm -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE"
fi
else
echo
echo "Merge conflicts not resolved yet, use:"
echo " git mergetool"
echo " git commit"
echo
echo "You can then complete the finish by running it again:"
echo " git flow feature finish $NAME"
echo
exit 1
fi
fi
# Sanity checks
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" "$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
run_pre_hook "$NAME" "$ORIGIN" "$BRANCH"
# If the user wants to rebase, do that first
if flag rebase; then
local _rebase_opts=""
if flag preserve_merges; then
_rebase_opts="$_rebase_opts -p"
fi
if flag showcommands; then
_rebase_opts="$_rebase_opts --showcommands"
fi
if ! git flow feature rebase $_rebase_opts "$NAME"; then
warn "Finish was aborted due to conflicts during rebase."
warn "Please finish the rebase manually now."
warn "When finished, re-run:"
warn " git flow feature finish '$NAME' '$BASE_BRANCH'"
exit 1
fi
fi
# Merge into BASE
git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'."
if noflag squash; then
if flag no_ff; then
git_do merge --no-ff "$BRANCH"
else
if [ "$(git rev-list -n2 "$BASE_BRANCH..$BRANCH" | wc -l)" -eq 1 ]; then
git_do merge --ff "$BRANCH"
else
git_do merge --no-ff "$BRANCH"
fi
fi
else
git_do merge --squash "$BRANCH"
flag squash_info && gitflow_create_squash_message "Merged feature branch '$BRANCH'" "$BASE_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG"
git_do commit
fi
if [ $? -ne 0 ]; then
# Oops.. we have a merge conflict!
# Write the given $BASE_BRANCH to a temporary file as we will
# be needing it later.
mkdir -p "$DOT_GIT_DIR/.gitflow"
echo "$BASE_BRANCH" > "$DOT_GIT_DIR/.gitflow/MERGE_BASE"
echo
echo "There were merge conflicts. To resolve the merge conflict manually, use:"
echo " git mergetool"
echo " git commit"
echo
echo "You can then complete the finish by running it again:"
echo " git flow feature finish $NAME"
echo
exit 1
fi
run_post_hook "$NAME" "$ORIGIN" "$BRANCH"
# When no merge conflict is detected, just clean up the feature branch
gitflow_config_remove_base_branch "$BRANCH"
echo $(date +%s) >> "./.git/.gitflow/.timelog-feature-$NAME"
LAST_TIME=$(tail -1 .git/.gitflow/.timelog-feature-$NAME | head -1)
PREV_TIME=$(tail -2 .git/.gitflow/.timelog-feature-$NAME | head -1)
TIME_USED=$((LAST_TIME-PREV_TIME))
echo "$TIME_USED" >> "./.git/.gitflow/.seconds-feature-$NAME"
if [ -f ./.git/.gitflow/.breaktime-feature-$NAME ];
then
TOTAL_BREAK_TIME=$(awk '{ sum += $1 } END { print sum }' ./.git/.gitflow/.breaktime-feature-$NAME)
else
TOTAL_BREAK_TIME=0
fi
TOTAL_TIME=$(awk '{ sum += $1 } END { print sum }' ./.git/.gitflow/.seconds-feature-$NAME)
TIME_EXPECTED=$(head -n 1 ./.git/.gitflow/.timelog-feature-$NAME)
FINALTIME=$((TOTAL_TIME/86400))" days "$(date -d "1970-01-01 + $TOTAL_TIME seconds" "+%H hours %M minutes %S seconds")
TOTAL_TIME_OFF=$((TOTAL_BREAK_TIME/86400))" days "$(date -d "1970-01-01 + $TOTAL_BREAK_TIME seconds" "+%H hours %M minutes %S seconds")
git commit --allow-empty -m "--Flow message(finish) --$BRANCH was completed on $(date), total time taken:$FINALTIME expectde time was $TIME_EXPECTED hour(s), Time spent on breaks was $TOTAL_TIME_OFF"
helper_finish_cleanup
}
helper_finish_cleanup() {
local keepmsg remotebranchdeleted localbranchdeleted
# Sanity checks
require_branch "$BRANCH"
require_clean_working_tree
remotebranchdeleted=$FLAGS_FALSE
localbranchdeleted=$FLAGS_FALSE
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
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
if flag push; then
git_do push "$ORIGIN" "$BASE_BRANCH" || die "Could not push branch '$BASE_BRANCH' to remote '$ORIGIN'."
fi
echo
echo "Summary of actions:"
echo "- The feature branch '$BRANCH' was merged into '$BASE_BRANCH'"
#echo "- Merge conflicts were resolved" # TODO: Add this line when it's supported
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 "- Feature branch '$BRANCH' "$keepmsg
echo "- You are now on branch '$(git_current_branch)'"
echo
}
cmd_publish() {
OPTIONS_SPEC="\
git flow feature publish [-h] [<name>]
Publish feature branch <name> on $ORIGIN.
When <name> is omitted the current branch is used, but only if it's a feature branch.
--
h,help! Show this help
showcommands! Show git commands while executing them
"
# Parse arguments
parse_args "$@"
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
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 "$NAME" "$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 "$NAME" "$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 feature track [-h] <name>
Start tracking feature <name> that is shared on $ORIGIN
--
h,help! Show this help
showcommands! Show git commands while executing them
"
# Parse arguments
parse_args "$@"
gitflow_require_name_arg
# Sanity checks
require_clean_working_tree
require_local_branch_absent "$BRANCH"
run_pre_hook "$NAME" "$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'."
run_post_hook "$NAME" "$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_diff() {
OPTIONS_SPEC="\
git flow feature diff [-h] [<name|nameprefix>]
Show all changes in <name> that are not in the base
--
h,help! Show this help
showcommands! Show git commands while executing them
"
local base
# Parse arguments
parse_args "$@"
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
fi
base=$(gitflow_config_get_base_branch $BRANCH)
base=${base:-$DEVELOP_BRANCH}
git_do diff "$base..$BRANCH"
}
cmd_checkout() {
OPTIONS_SPEC="\
git flow feature checkout [-h] [<name|nameprefix>]
Switch to feature branch <name>
--
h,help! Show this help
showcommands! Show git commands while executing them
"
# Parse arguments
parse_args "$@"
NAME=$(gitflow_resolve_nameprefix "$NAME" "$PREFIX")
if [ $? -eq 0 ]; then
BRANCH=$PREFIX$NAME
git_do checkout "$BRANCH" || die "Could not check out branch '$BRANCH'."
fi
}
cmd_co() {
# Alias for checkout
cmd_checkout "$@"
}
cmd_rebase() {
OPTIONS_SPEC="\
git flow feature 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 "feature.rebase.interactive" "interactive"
gitflow_override_flag_boolean "feature.rebase.preserve-merges" "preserve_merges"
# Parse arguments
parse_args "$@"
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
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'..."
require_clean_working_tree
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 feature 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"
}
avoid_accidental_cross_branch_action() {
local current_branch
current_branch=$(git_current_branch)
if [ "$BRANCH" != "$current_branch" ]; then
warn "Trying to pull from '$BRANCH' while currently on branch '$current_branch'."
warn "To avoid unintended merges, git-flow aborted."
return 1
fi
return 0
}
cmd_pull() {
OPTIONS_SPEC="\
git flow feature pull [-h] <remote> [<name>]
Pull feature <name> from <remote>
--
h,help! Show this help
showcommands! Show git commands while executing them
"
local current_branch
# Define flags
DEFINE_boolean 'rebase' false "pull with rebase" r
warn "The command 'git flow feature pull' will be deprecated per version 2.0.0. Use 'git flow feature track' instead."
# Parse arguments
parse_remote_name "$@"
if [ -z "$REMOTE" ]; then
die "Name a remote explicitly."
fi
# Use current branch if no name is given
if [ "$NAME" = "" ]; then
gitflow_use_current_branch_name
fi
# To avoid accidentally merging different feature branches into each other,
# die if the current feature branch differs from the requested $NAME
# argument.
current_branch=$(git_current_branch)
if startswith "$current_branch" "$PREFIX"; then
# We are on a local feature branch already, so $BRANCH must be equal to
# the current branch
avoid_accidental_cross_branch_action || die
fi
require_clean_working_tree
run_pre_hook "$NAME" "$REMOTE" "$BRANCH"
if git_local_branch_exists "$BRANCH"; then
# Again, avoid accidental merges
avoid_accidental_cross_branch_action || die
# We already have a local branch called like this, so simply pull the
# remote changes in
if flag rebase; then
if ! git_do pull --rebase -q "$REMOTE" "$BRANCH"; then
warn "Pull was aborted. There might be conflicts during rebase or '$REMOTE' might be inaccessible."
exit 1
fi
else
git_do pull -q "$REMOTE" "$BRANCH" || die "Failed to pull from remote '$REMOTE'."
fi
echo "Pulled $REMOTE's changes into $BRANCH."
else
# Setup the local branch clone for the first time
git_do fetch -q "$REMOTE" "$BRANCH" || die "Could not fetch branch '$BRANCH' from remote '$REMOTE'." # Stores in FETCH_HEAD
git_do branch --no-track "$BRANCH" FETCH_HEAD || die "Branch failed."
git_do checkout -q "$BRANCH" || die "Could not check out branch '$BRANCH'."
echo "Created local branch $BRANCH based on $REMOTE's $BRANCH."
fi
run_post_hook "$NAME" "$REMOTE" "$BRANCH"
}
cmd_delete() {
OPTIONS_SPEC="\
git flow feature delete [-h] [-f] [-r] <name>
Delete a given feature 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 "feature.delete.force" "force"
gitflow_override_flag_boolean "feature.delete.remote" "remote"
# Parse arguments
parse_args "$@"
gitflow_require_name_arg
# Sanity checks
require_branch "$BRANCH"
BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH)
BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH}
run_pre_hook "$NAME" "$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" "$BASE_BRANCH"; then
git_do branch -d "$BRANCH" || die "Could not delete the $BRANCH."
if flag remote; then
git_do push "$ORIGIN" :"$BRANCH" || die "Could not delete the remote $BRANCH in $ORIGIN."
fi
else
if flag force; then
git_do branch -D "$BRANCH" || die "Could not delete the $BRANCH."
if flag remote; then
git_do push "$ORIGIN" :"$BRANCH" || die "Could not delete the remote $BRANCH in $ORIGIN."
fi
else
die "Feature branch '$BRANCH' has been not been merged yet. Use -f to force the deletion."
fi
fi
gitflow_config_remove_base_section "$BRANCH"
run_post_hook "$NAME" "$ORIGIN" "$BRANCH"
echo
echo "Summary of actions:"
echo "- Feature branch '$BRANCH' has been deleted."
flag remote && echo "- Feature branch '$BRANCH' in '$ORIGIN' has been deleted."
echo "- You are now on branch '$(git_current_branch)'"
echo
}
cmd_pause() {
OPTIONS_SPEC="\
git flow feature pause [-h]
Use this to pause the timer at any time for a coffee.
----
h,help! Show this help
"
parse_args "$@"
local current_branch
local current_name
current_branch=$(git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g')
current_name=$(echo "$current_branch" | sed "s ^$PREFIX g")
echo $(date +%s) >> "./.git/.gitflow/.timelog-feature-$current_name"
LAST_TIME=$(tail -1 .git/.gitflow/.timelog-feature-$current_name | head -1)
PREV_TIME=$(tail -2 .git/.gitflow/.timelog-feature-$current_name | head -1)
TIME_USED=$((LAST_TIME-PREV_TIME))
echo "$TIME_USED" >> "./.git/.gitflow/.seconds-feature-$current_name"
seconds=$TIME_USED; TIMESTAMP=$((seconds/86400))" days "$(date -d "1970-01-01 + $seconds seconds" "+%H hours %M minutes %S seconds")
git add --all .
git commit -m "$current_branch/WIP"
git commit --allow-empty -m "--Flow message(pause) -- $current_branch/WIP time-paused:$(date), time taken thus far:$TIMESTAMP"
git checkout -b "$current_branch-paused" "flopharn"
git rm * --quiet --ignore-unmatch
echo
echo "Summary of actions:"
echo "- Created orphan branch called '$current_branch-paused'"
echo "- You are now free to take a break, you have spent $TIMESTAMP in this session"
echo ""
echo "Now, have some coffee and when you are done, use:"
echo ""
echo " git flow feature resume $current_name"
echo
}
cmd_interrupt() {
OPTIONS_SPEC="\
git flow feature interrupt [-h]
Use this to pause the timer. Resuming the feature will ask you for a reason
----
h,help! Show this help
"
parse_args "$@"
local current_branch
local current_name
current_branch=$(git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g')
current_name=$(echo "$current_branch" | sed "s ^$PREFIX g")
echo $(date +%s) >> "./.git/.gitflow/.timelog-feature-$current_name"
LAST_TIME=$(tail -1 .git/.gitflow/.timelog-feature-$current_name | head -1)
PREV_TIME=$(tail -2 .git/.gitflow/.timelog-feature-$current_name | head -1)
TIME_USED=$((LAST_TIME-PREV_TIME))
echo "$TIME_USED" >> "./.git/.gitflow/.seconds-feature-$current_name"
echo "dummy" >> "./.git/.gitflow/.interrupt-feature-$current_name"
seconds=$TIME_USED; TIMESTAMP=$((seconds/86400))" days "$(date -d "1970-01-01 + $seconds seconds" "+%H hours %M minutes %S seconds")
git add --all .
git commit -m "$current_branch/WIP"
git commit --allow-empty -m "--Flow message(interrupt) --$current_branch/WIP You were disturbed on $(date), time taken so far:$TIMESTAMP"
git checkout -b "$current_branch-paused" "flopharn"
git rm * --quiet --ignore-unmatch
echo
echo "Summary of actions:"
echo "- Created orphan branch called '$current_branch-paused'"
echo "- You are now free to take a break, you have spent $TIMESTAMP in this session"
echo ""
echo "Now, have some coffee and when you are done, use:"
echo ""
echo " git flow feature resume $current_branch"
echo
}
cmd_resume() {
OPTIONS_SPEC="\
git flow feature resume [-h] <name>
Allows you to continue working on a feature after using pause or interrupt
----
h,help! Show this help
"
parse_args "$@"
gitflow_require_name_arg
# sanity checks
require_branch "$BRANCH"
if [ -f ./.git/.gitflow/.interrupt-feature-$NAME ];
then
echo "Why were you interrupted?"
read INTERRUPT_REASON
rm ./.git/.gitflow/.interrupt-feature-$NAME
else
INTERRUPT_REASON="No reason :)"
fi
LAST_TIME=$(date +%s)
PREV_TIME=$(tail -1 .git/.gitflow/.timelog-feature-$NAME | head -1)
BREAK_TIME=$((LAST_TIME-PREV_TIME))
echo "$BREAK_TIME" >> "./.git/.gitflow/.breaktime-feature-$NAME"
seconds=$BREAK_TIME; TIME_OFF=$((seconds/86400))" days "$(date -d "1970-01-01 + $seconds seconds" "+%H hours %M minutes %S seconds")
git add .
git checkout "$BRANCH"
git branch -D "$BRANCH-paused"
git commit --allow-empty -m "--Flow message(resume) --$BRANCH/Back to Work at:$(date) Time off:$TIME_OFF, Reason: $INTERRUPT_REASON"
echo $(date +%s) >> "./.git/.gitflow/.timelog-feature-$NAME"
echo
echo "Summary of actions:"
echo "Switches you back to the '$BRANCH' branch"
echo "- You are now on branch '$BRANCH'"
echo ""
echo "Remmember when you need a break use:"
echo ""
echo " git flow feature pause"
echo
}
cmd_review() {
OPTIONS_SPEC="\
git flow feature review [-h] <name>
Publishes a feature and submits a pull request if gitlab/github is configured
--
h,help! Show this help
"
parse_args "$@"
expand_nameprefix_arg
# sanity checks
require_clean_working_tree
require_branch "$BRANCH"
git_do fetch -q "$ORIGIN"
# require_branch_absent "$ORIGIN/$BRANCH"
# create remote branch
git_do push "$ORIGIN" "$BRANCH:refs/heads/$BRANCH"
git_do fetch -q "$ORIGIN"
# configure remote tracking
git_do config "branch.$BRANCH.remote" "$ORIGIN"
git_do config "branch.$BRANCH.merge" "refs/heads/$BRANCH"
git_do checkout "$BRANCH"
echo $(date +%s) >> "./.git/.gitflow/.timelog-feature-$NAME"
LAST_TIME=$(tail -1 .git/.gitflow/.timelog-feature-$NAME | head -1)
PREV_TIME=$(tail -2 .git/.gitflow/.timelog-feature-$NAME | head -1)
TIME_USED=$((LAST_TIME-PREV_TIME))
echo "$TIME_USED" >> "./.git/.gitflow/.seconds-feature-$NAME"
if [ -f ./.git/.gitflow/.breaktime-feature-$NAME ];
then
TOTAL_BREAK_TIME=$(awk '{ sum += $1 } END { print sum }' ./.git/.gitflow/.breaktime-feature-$NAME)
else
TOTAL_BREAK_TIME=0
fi
TOTAL_TIME=$(awk '{ sum += $1 } END { print sum }' ./.git/.gitflow/.seconds-feature-$NAME)
TIME_EXPECTED=$(head -n 1 ./.git/.gitflow/.timelog-feature-$NAME)
FINALTIME=$((TOTAL_TIME/86400))" days "$(date -d "1970-01-01 + $TOTAL_TIME seconds" "+%H hours %M minutes %S seconds")
TOTAL_TIME_OFF=$((TOTAL_BREAK_TIME/86400))" days "$(date -d "1970-01-01 + $TOTAL_BREAK_TIME seconds" "+%H hours %M minutes %S seconds")
git commit --allow-empty -m "--Flow message(finish) --$BRANCH was completed on $(date), total time taken:$FINALTIME expected time was $TIME_EXPECTED hour(s), Time spent on breaks was $TOTAL_TIME_OFF"
GIT_URL=$(git config --get remote.origin.url)
GIT_URL_WITHOUT_SUFFIX="${GIT_URL%.*}"
REPO="$(basename "${GIT_URL_WITHOUT_SUFFIX}")"
URL_WITH_OWNER="$(dirname "${GIT_URL_WITHOUT_SUFFIX})")"
OWNER=$(basename $(echo $URL_WITH_OWNER | tr ":" /))
DEVELOPMENT_BRANCH=$(git config --get gitflow.branch.develop)
if [ -f ./.git/.gitflow/.github_token ];
then
GITHUB_USERNAME=$(tail -1 ./.git/.gitflow/.github_username | head -1)
GITHUB_TOKEN=$(tail -1 ./.git/.gitflow/.github_token | head -1)
GITHUB_REQUEST=$(curl -X POST --write-out %{http_code} --silent --output /dev/null -H "Content-Type: application/json" \
-H "Cache-Control: no-cache" \
--user $GITHUB_USERNAME:$GITHUB_TOKEN \
-d '{
"title":"'"$GITHUB_USERNAME"' submitted '"$BRANCH"' branch for review",
"head":"'"$BRANCH"'",
"base":"'"$DEVELOPMENT_BRANCH"'",
"body":"'"$GITHUB_USERNAME"' is asking for code review. Total time taken:'"$FINALTIME"' expected time was '"$TIME_EXPECTED"' hour(s), Time spent on breaks was '"$TOTAL_TIME_OFF"' -- message by gitflow",
"maintainer_can_modify": true
}' \
"https://api.github.com/repos/$OWNER/$REPO/pulls")
if [ "$GITHUB_REQUEST" -gt 300 ]
then
echo "Failed to create pull request"
else
echo "Pull request created on github please inform the code reviewer by mentioning them in the comments"
fi
fi
if [ -f ./.git/.gitflow/.gitlab_token ];
then
GITLAB_TOKEN=$(tail -1 ./.git/.gitflow/.gitlab_token | head -1)
USER_NAME=$(git config --get --global user.name)
GITLAB_REQUEST=$(curl -X POST --write-out %{http_code} --silent --output /dev/null -H "PRIVATE-TOKEN: $GITLAB_TOKEN" -H "Content-Type: application/json" -H "Cache-Control: no-cache" -H "Postman-Token: 209ed2f2-a7bd-ab33-a432-1d884669976b" -d '{
"target_branch": "'"$DEVELOPMENT_BRANCH"'",
"source_branch": "'"$BRANCH"'",
"title": "'"$BRANCH Merge Request by $USER_NAME"'",
"body":"'"$USER_NAME"' is asking for code review. Total time taken:'"$FINALTIME"' expected time was '"$TIME_EXPECTED"' hour(s), Time spent on breaks was '"$TOTAL_TIME_OFF"' -- message by gitflow"
}' "https://gitlab.com/api/v3/projects/$OWNER%2F$REPO/merge_requests")
if [ "$GITLAB_REQUEST" -gt 300 ]
then
echo "Failed to create merge request"
else
echo "Merge request created on gitlab please inform the code reviewer by mentioning them in the comments"
fi
fi
git pause
git checkout $DEVELOPMENT_BRANCH
git pull
echo
echo "Summary of actions:"
echo "- A new remote branch '$BRANCH' was created"
echo "- The local branch '$BRANCH' was configured to track the remote branch"
echo "- You are now on branch '$DEVELOPMENT_BRANCH'"
echo
}
\ No newline at end of file
#
# 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-2016 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"
require_clean_working_tree
gitflow_config_set_base_branch $base $BRANCH
# 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"
# 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'..."
require_clean_working_tree
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"
# 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
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
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_do push "$ORIGIN" :"$BRANCH" || die "Could not delete the remote $BRANCH in $ORIGIN."
fi
else
if flag force; then
git_do branch -D "$BRANCH" || die "Could not delete the $BRANCH."
if flag remote; then
git_do push "$ORIGIN" :"$BRANCH" || die "Could not delete the remote $BRANCH in $ORIGIN."
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
}
#
# 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-2016 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.
#
usage() {
OPTIONS_SPEC="\
git flow init
Initialize a new git repo with support for the branching model.
----
git flow init gitlab
Allow flow to automatically create merge requests on your behalf on gitlab
----
A personal access token is needed, create one at https://gitlab.com/profile/personal_access_tokens
git flow init github
Allow flow to automatically create pull requests on your behalf on github
----
Your username and a personal access token are need, create one at https://github.com/settings/tokens
----
For more specific help type the command followed by --help
--
"
flags_help
}
# Parse arguments and set common variables
parse_args() {
FLAGS "$@" || exit $?
eval set -- "${FLAGS_ARGV}"
}
# Default entry when no SUBACTION is given
cmd_default() {
OPTIONS_SPEC="\
git flow init [-h] [-d] [-f]
Setup a git repository for git flow usage. Can also be used to start a git repository.
--
h,help! Show this help
showcommands! Show git commands while executing them
d,[no]defaults Use default branch naming conventions
f,[no]force Force setting of gitflow branches, even if already configured
Use config file location
local! use repository config file
global! use global config file
system! use system config file
file= use given config file
"
git config alias.start 'flow feature start'
git config alias.finish 'flow feature finish'
git config alias.fin 'flow feature finish'
git config alias.stop 'flow feature finish'
git config alias.resume 'flow feature resume'
git config alias.res 'flow feature resume'
git config alias.interrupt 'flow feature interrupt'
git config alias.int 'flow feature interrupt'
git config alias.pause 'flow feature pause'
git config alias.p 'flow feature pause'
git config alias.hotfix 'flow hotfix'
git config alias.hotfix 'flow hotfix'
git config alias.support 'flow support'
git config alias.release 'flow release'
local gitflow_config_option should_check_existence branchcount guess
local master_branch develop_branch default_suggestion answer prefix
# Define flags
DEFINE_boolean 'force' false 'force setting of gitflow branches, even if already configured' f
DEFINE_boolean 'defaults' false 'use default branch naming conventions' d
DEFINE_boolean 'local' false 'use repository config file'
DEFINE_boolean 'global' false 'use global config file'
DEFINE_boolean 'system' false 'use system config file'
DEFINE_string 'file' "" 'use given config file'
# Override defaults with values from config
gitflow_override_flag_boolean "init.defaults" "defaults"
# Parse arguments
parse_args "$@"
if [ "$FLAGS_file" != "" ]; then
gitflow_config_option="--file '$FLAGS_file''"
elif flag local; then
gitflow_config_option="--local"
elif flag global; then
gitflow_config_option="--global"
elif flag system; then
gitflow_config_option="--system"
else
gitflow_config_option=""
fi
if ! git rev-parse --git-dir >/dev/null 2>&1; then
git_do init
else
# Assure that we are not working in a repo with local changes
git_repo_is_headless || require_clean_working_tree
fi
# Running git flow init on an already initialized repo is fine
if gitflow_is_initialized && ! flag force; then
warn "Already initialized for gitflow."
warn "To force reinitialization, use: git flow init -f"
exit 0
fi
if flag defaults; then
warn "Using default branch names."
fi
# Add a master branch if no such branch exists yet
if gitflow_has_master_configured && ! flag force; then
master_branch=$(git config --get gitflow.branch.master)
else
# Two cases are distinguished:
# 1. A fresh git repo (without any branches)
# We will create a new master/develop branch for the user
# 2. Some branches do already exist
# We will disallow creation of new master/develop branches and
# rather allow to use existing branches for git-flow.
branch_count=$(git_local_branches | wc -l)
if [ "$branch_count" -eq 0 ]; then
echo "No branches exist yet. Base branches must be created now."
should_check_existence=NO
default_suggestion=$(git config --get gitflow.branch.master || echo master)
else
echo
echo "Which branch should be used for bringing forth production releases?"
git_local_branches | sed 's/^.*$/ - &/g'
should_check_existence=YES
default_suggestion=
for guess in $(git config --get gitflow.branch.master) 'production' 'main' 'master'; do
if git_local_branch_exists "$guess"; then
default_suggestion="$guess"
break
fi
done
fi
if [ -z $default_suggestion ] && flag defaults; then
should_check_existence=YES
default_suggestion=$(git config --get gitflow.branch.master || echo master)
fi
printf "Branch name for production releases: [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
master_branch=${answer:-$default_suggestion}
# Check existence in case of an already existing repo
if [ "$should_check_existence" = "YES" ]; then
# If no local branch exists and a remote branch of the same
# name exists, checkout that branch and use it for master
if ! git_local_branch_exists "$master_branch" && git_remote_branch_exists "origin/$master_branch"; then
git_do branch "$master_branch" "origin/$master_branch" >/dev/null 2>&1
elif ! git_local_branch_exists "$master_branch"; then
die "Local branch '$master_branch' does not exist."
fi
fi
# Store the name of the master branch
git_do config $gitflow_config_option gitflow.branch.master "$master_branch"
fi
# Add a develop branch if no such branch exists yet
if gitflow_has_develop_configured && ! flag force; then
develop_branch=$(git config --get gitflow.branch.develop)
else
# Again, the same two cases as with the master selection are
# considered (fresh repo or repo that contains branches)
branch_count=$(git_local_branches | grep -v "^${master_branch}\$" | wc -l)
if [ "$branch_count" -eq 0 ]; then
should_check_existence=NO
default_suggestion=$(git config --get gitflow.branch.develop || echo develop)
else
echo
echo "Which branch should be used for integration of the \"next release\"?"
git_local_branches | grep -v "^${master_branch}\$" | sed 's/^.*$/ - &/g'
should_check_existence=YES
default_suggestion=
for guess in $(git config --get gitflow.branch.develop) 'develop' 'int' 'integration' 'master'; do
if git_local_branch_exists "$guess" && [ "$guess" != "$master_branch" ]; then
default_suggestion="$guess"
break
fi
done
fi
if [ -z $default_suggestion ] && flag defaults; then
should_check_existence=YES
default_suggestion=$(git config --get gitflow.branch.develop || echo develop)
fi
printf "Branch name for \"next release\" development: [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
develop_branch=${answer:-$default_suggestion}
if [ "$master_branch" = "$develop_branch" ]; then
die "Production and integration branches should differ."
fi
# Check existence in case of an already existing repo
if [ "$should_check_existence" = "YES" ]; then
git_local_branch_exists "$develop_branch" || die "Local branch '$develop_branch' does not exist."
fi
# Store the name of the develop branch
git_do config $gitflow_config_option gitflow.branch.develop "$develop_branch"
fi
# Creation of HEAD
# ----------------
# We create a HEAD now, if it does not exist yet (in a fresh repo). We need
# it to be able to create new branches.
local created_gitflow_branch=0
if ! git rev-parse --quiet --verify HEAD >/dev/null 2>&1; then
git_do symbolic-ref HEAD "refs/heads/$master_branch"
git_do commit --allow-empty --quiet -m "Initial commit"
created_gitflow_branch=1
fi
# Creation of master
# ------------------
# At this point, there always is a master branch: either it existed already
# (and was picked interactively as the production branch) or it has just
# been created in a fresh repo
# Creation of develop
# -------------------
# The develop branch possibly does not exist yet. This is the case when,
# in a git init'ed repo with one or more commits, master was picked as the
# default production branch and develop was "created". We should create
# the develop branch now in that case (we base it on master, of course)
if ! git_local_branch_exists "$develop_branch"; then
if git_remote_branch_exists "origin/$develop_branch"; then
git_do branch "$develop_branch" "origin/$develop_branch" >/dev/null 2>&1
else
git_do branch --no-track "$develop_branch" "$master_branch"
fi
created_gitflow_branch=1
fi
# Assert the git-flow repo has been correctly initialized
gitflow_is_initialized
# Switch to develop branch if its newly created
if [ $created_gitflow_branch -eq 1 ]; then
git_do checkout -q "$develop_branch" || die "Could not check out branch '$develop_branch'."
fi
# Ask the user for naming conventions (branch and tag prefixes )
if flag force || \
! git config --get gitflow.prefix.feature >/dev/null 2>&1 ||
! git config --get gitflow.prefix.bugfix >/dev/null 2>&1 ||
! git config --get gitflow.prefix.release >/dev/null 2>&1 ||
! git config --get gitflow.prefix.hotfix >/dev/null 2>&1 ||
! git config --get gitflow.prefix.support >/dev/null 2>&1 ||
! git config --get gitflow.prefix.versiontag >/dev/null 2>&1; then
echo
echo "How to name your supporting branch prefixes?"
fi
# Feature branches
if ! git config --get gitflow.prefix.feature >/dev/null 2>&1 || flag force; then
default_suggestion=$(git config --get gitflow.prefix.feature || echo feature/)
printf "Feature branches? [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
git_do config $gitflow_config_option gitflow.prefix.feature "$prefix"
fi
# Bugfix branches
if ! git config --get gitflow.prefix.bugfix >/dev/null 2>&1 || flag force; then
default_suggestion=$(git config --get gitflow.prefix.bugfix || echo bugfix/)
printf "Bugfix branches? [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
git_do config $gitflow_config_option gitflow.prefix.bugfix "$prefix"
fi
# Release branches
if ! git config --get gitflow.prefix.release >/dev/null 2>&1 || flag force; then
default_suggestion=$(git config --get gitflow.prefix.release || echo release/)
printf "Release branches? [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
git_do config $gitflow_config_option gitflow.prefix.release "$prefix"
fi
# Hotfix branches
if ! git config --get gitflow.prefix.hotfix >/dev/null 2>&1 || flag force; then
default_suggestion=$(git config --get gitflow.prefix.hotfix || echo hotfix/)
printf "Hotfix branches? [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
git_do config $gitflow_config_option gitflow.prefix.hotfix "$prefix"
fi
# Support branches
if ! git config --get gitflow.prefix.support >/dev/null 2>&1 || flag force; then
default_suggestion=$(git config --get gitflow.prefix.support || echo support/)
printf "Support branches? [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
git_do config $gitflow_config_option gitflow.prefix.support "$prefix"
fi
# Version tag prefix
if ! git config --get gitflow.prefix.versiontag >/dev/null 2>&1 || flag force; then
default_suggestion=$(git config --get gitflow.prefix.versiontag || echo "")
printf "Version tag prefix? [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
git_do config $gitflow_config_option gitflow.prefix.versiontag "$prefix"
fi
# Paths
if ! git config --get gitflow.path.hooks >/dev/null 2>&1 || flag force; then
DOT_GIT_DIR=$(git rev-parse --git-dir)
DOT_GIT_DIR=$(cd "$DOT_GIT_DIR" >/dev/null 2>&1 && pwd)
default_suggestion=$(git config --get gitflow.path.hooks || echo "$DOT_GIT_DIR"/hooks)
printf "Hooks and filters directory? [$default_suggestion] "
if noflag defaults; then
read answer
else
printf "\n"
fi
[ "$answer" = "-" ] && hooks_dir= || hooks_dir=${answer:-$default_suggestion}
git_do config $gitflow_config_option gitflow.path.hooks "$hooks_dir"
fi
mkdir -p "./.git/.gitflow"
git checkout --orphan flopharn
git rm * --quiet --ignore-unmatch
git commit --allow-empty -m "flopharn was created successfully"
git checkout $develop_branch
if git remote -v | grep github > /dev/null
then
configure_github_api
fi
if git remote -v | grep gitlab > /dev/null
then
configure_gitlab_api
fi
# TODO: what to do with origin?
}
cmd_help() {
usage
exit 0
}
cmd_github() {
OPTIONS_SPEC="\
git flow init github
Allow flow to automatically create pull requests on your behalf on github
----
Your username and a personal access token are need, create one at https://github.com/settings/tokens
"
parse_args "$@"
configure_github_api
}
cmd_gitlab() {
OPTIONS_SPEC="\
git flow init gitlab
Allow flow to automatically create merge requests on your behalf on gitlab
----
A personal access token is needed, create one at https://gitlab.com/profile/personal_access_tokens
"
parse_args "$@"
configure_gitlab_api
}
configure_github_api() {
read -r -p "Do you wish to automatically create merge requests on github? [y/N] " response
case "$response" in
[yY])
echo "Please provide your username."
read GITHUB_USERNAME
echo "Please provide a valid access token."
read GITHUB_TOKEN
TEST_GITHUB_AUTH=$(curl --write-out %{http_code} --silent --output /dev/null -u $GITHUB_USERNAME:$GITHUB_TOKEN https://api.github.com/user)
if [ "$TEST_GITHUB_AUTH" -eq 200 ]
then
echo $GITHUB_TOKEN > "./.git/.gitflow/.github_token"
echo $GITHUB_USERNAME > "./.git/.gitflow/.github_username"
echo "Authenticated successfully"
else
echo "Authentication failed"
configure_github_api
fi
;;
*)
echo "Cool"
;;
esac
}
configure_gitlab_api() {
read -r -p "Do you wish to automatically create merge requests on gitlab? [y/N] " response
case "$response" in
[yY])
echo "Please provide a valid Personal Access Token."
read GITLAB_TOKEN
TEST_GITLAB_AUTH=$(curl --write-out %{http_code} --silent --output /dev/null --header "PRIVATE-TOKEN: $GITLAB_TOKEN" https://gitlab.com/api/v3/user)
if [ "$TEST_GITLAB_AUTH" -eq 200 ]
then
echo $GITLAB_TOKEN > "./.git/.gitflow/.gitlab_token"
echo "Authenticated successfully"
else
echo "Authentication failed"
configure_gitlab_api
fi
;;
*)
echo "Cool"
;;
esac
}
\ No newline at end of file
#
# 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-2016 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
gitflow_load_settings
}
usage() {
OPTIONS_SPEC="\
git flow log
shows current branch log compared to develop
'git help log' for arguments
--
"
flags_help
}
# Parse arguments and set common variables
parse_args() {
FLAGS "$@" || exit $?
eval set -- "${FLAGS_ARGV}"
}
cmd_default() {
cmd_list "$@"
}
cmd_list() {
OPTIONS_SPEC="\
git flow feature log [<options>]
Show log on <feature> branch since the fork of <develop> branch
Options come from git log
--
h,help! Show this help
showcommands! Show git commands while executing them
"
# Parse arguments
parse_args "$@"
# get base branch from current branch
local base=$(gitflow_config_get_base_branch $(git_current_branch))
# no base branch found, comparing against $master
if [ -z $base ]; then
base=$MASTER_BRANCH
fi
# Get the log
echo "Comparing against \"$base\" branch\n"
git_do log "$@""$base.."
}
cmd_help() {
usage
exit 0
}
#
# 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-2016 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.
# 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="$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
run_post_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH"
# 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
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
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
gitflow_config_set_base_branch $base $BRANCH
require_no_existing_release_branches
# Sanity checks
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"
# 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
"
# 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
# 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"
# 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'..."
require_clean_working_tree
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_do push "$ORIGIN" :"$BRANCH" || die "Could not delete the remote $BRANCH in $ORIGIN."
fi
else
if flag force; then
git_do branch -D "$BRANCH" || die "Could not delete the $BRANCH."
if flag remote; then
git_do push "$ORIGIN" :"$BRANCH" || die "Could not delete the remote $BRANCH in $ORIGIN."
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
}
#
# 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-2016 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.support >/dev/null 2>&1 || die "Support 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.support)
}
usage() {
OPTIONS_SPEC="\
git flow support [list]
git flow support start
Manage your support branches.
For more specific help type the command followed by --help
--
"
flags_help
}
cmd_default() {
cmd_list "$@"
}
cmd_list() {
OPTIONS_SPEC="\
git flow support [list] [-h] [-v]
List all local support branches
--
h,help! Show this help
v,verbose Verbose (more) output
"
local support_branches current_branch width branch len
local base master_sha branch_sha
local tagname nicename
# Define flags
DEFINE_boolean 'verbose' false 'verbose (more) output' v
# Parse arguments
parse_args "$@"
support_branches=$(git_local_branches_prefixed "$PREFIX")
if [ -z "$support_branches" ]; then
warn "No support branches exist."
warn ""
warn "You can start a new support branch:"
warn ""
warn " git flow support start <name> <base>"
warn ""
exit 0
fi
current_branch=$(git_current_branch)
# Determine column width first
width=0
for branch in $support_branches; do
len=${#branch}
width=$(max $width $len)
done
width=$(($width+3-${#PREFIX}))
for branch in $support_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
tagname=$(git name-rev --tags --no-undefined --name-only "$base")
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
if [ -z $2 ]; then
BASE=''
else
BASE=$2
fi
BRANCH=$PREFIX$VERSION
}
cmd_start() {
OPTIONS_SPEC="\
git flow support start [-h] [-F] <version> <base>
Start a new support branch name <version> based on <base>
--
h,help! Show this help
showcommands! Show git commands while executing them
F,[no]fetch Fetch from origin before performing finish
"
# Define flags
DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F
# Override defaults with values from config
gitflow_override_flag_boolean "support.start.fetch" "fetch"
# Parse arguments
parse_args "$@"
gitflow_require_version_arg
gitflow_require_base_arg
# Sanity checks
require_clean_working_tree
# Fetch remote changes
if flag fetch; then
git_fetch_branch "$ORIGIN" "$BASE"
fi
git_is_ancestor "$BASE" "$MASTER_BRANCH" || die "Given base '$BASE' is not a valid commit on '$MASTER_BRANCH'."
require_branch_absent "$BRANCH"
# Create branch
git_do checkout -b "$BRANCH" "$BASE" || die "Could not create support branch '$BRANCH'."
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
}
cmd_rebase() {
OPTIONS_SPEC="\
git flow support 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 "support.rebase.interactive" "interactive"
gitflow_override_flag_boolean "support.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'..."
require_clean_working_tree
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 support 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"
}
#
# 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-2016 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.
#
GITFLOW_VERSION=0.4.11
initialize() {
# A function can not be empty. Comments count as empty.
local FOO=''
}
usage() {
OPTIONS_SPEC="\
git flow version
Shows version information.
For more specific help type the command followed by --help
--
"
flags_help
}
cmd_default() {
echo "$GITFLOW_VERSION (DREIDEV Edition -- drazious)"
}
cmd_help() {
usage
exit 0
}
#
# 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-2016 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.
#
#
# Common functionality
#
# Shell output
warn() { echo "$@" >&2; }
die() { warn "Fatal: $@"; exit 1; }
die_help() { warn $@; flags_help; exit 1; }
escape() {
echo "$1" | sed 's/\([\.\$\*]\)/\\\1/g'
}
#
# String contains function
# $1 haystack
# $2 Needle
#
contains() {
local return
case $1 in
*$2*)
return=$FLAGS_TRUE
;;
*)
return=$FLAGS_FALSE
;;
esac
return $return
}
# Basic math
min() { [ "$1" -le "$2" ] && echo "$1" || echo "$2"; }
max() { [ "$1" -ge "$2" ] && echo "$1" || echo "$2"; }
# Basic string matching
startswith() { [ "$1" != "${1#$2}" ]; }
endswith() { [ "$1" != "${1%$2}" ]; }
# Convenience functions for checking shFlags flags
flag() { local FLAG; eval FLAG='$FLAGS_'$1; [ $FLAG -eq $FLAGS_TRUE ]; }
noflag() { local FLAG; eval FLAG='$FLAGS_'$1; [ $FLAG -ne $FLAGS_TRUE ]; }
# check_boolean
# Check if given value can be interpreted as a boolean
#
# This function determines if the passed parameter is a valid boolean value.
#
# Param $1: string Value to check if it's a valid boolean
#
# Return: string FLAGS_TRUE|FLAGS_FALSE|FLAGS_ERROR
# FLAGS_TRUE if the parameter is a boolean TRUE
# FLAGS_FALSE if the parameter is a boolean FALSE
# FLAGS_ERROR if the parameter is not a boolean
#
check_boolean() {
local _return _value
_value="${1}"
case "${_value}" in
${FLAGS_TRUE} | [yY] | [yY][eE][sS] | [tT] | [tT][rR][uU][eE])
_return=${FLAGS_TRUE}
;;
${FLAGS_FALSE} | [nN] | [nN][oO] | [fF] | [fF][aA][lL][sS][eE])
_return=${FLAGS_FALSE}
;;
*)
_return=${FLAGS_ERROR}
;;
esac
unset _value
return ${_return}
}
#
# Git specific common functionality
#
git_local_branches() { git for-each-ref --sort refname --format='%(refname:short)' refs/heads; }
git_remote_branches() { git for-each-ref --sort refname --format='%(refname:short)' refs/remotes; }
git_all_branches() { git for-each-ref --sort refname --format='%(refname:short)' refs/remotes refs/heads; }
git_all_tags() { git for-each-ref --format='%(refname:short)' refs/tags; }
git_local_branches_prefixed() {
[ -z $1 ] && die "Prefix parameter missing." # This should never happen.
git for-each-ref --format='%(refname:short)' refs/heads/$1\* ;
}
git_current_branch() {
local branch_name
branch_name="$(git symbolic-ref --quiet HEAD)"
[ -z $branch_name ] && branch_name="(unnamed branch)" || branch_name="$(git for-each-ref --format='%(refname:short)' $branch_name)"
echo "$branch_name"
}
git_is_clean_working_tree() {
git rev-parse --verify HEAD >/dev/null || exit 1
git update-index -q --ignore-submodules --refresh
# Check for unstaged changes
git diff-files --quiet --ignore-submodules || return 1
# Check for Uncommited changes
git diff-index --cached --quiet --ignore-submodules HEAD -- || return 2
return 0
}
git_repo_is_headless() {
! git rev-parse --quiet --verify HEAD >/dev/null 2>&1
}
git_local_branch_exists() {
[ -n "$1" ] || die "Missing branch name"
[ -n "$(git for-each-ref --format='%(refname:short)' refs/heads/$1)" ]
}
git_remote_branch_exists() {
[ -n "$1" ] || die "Missing branch name"
[ -n "$(git for-each-ref --format='%(refname:short)' refs/remotes/$1)" ]
}
git_remote_branch_delete() {
[ -n "$1" ] || die "Missing branch name"
if git_remote_branch_exists "$ORIGIN/$1"; then
git_do push "$ORIGIN" :"$1" || die "Could not delete the remote $1 in $ORIGIN."
else
warn "Trying to delete the remote branch $1, but it does not exists in $ORIGIN"
fi
}
git_branch_exists() {
[ -n "$1" ] || die "Missing branch name"
git_local_branch_exists "$1" || git_remote_branch_exists "$ORIGIN/$1"
}
git_tag_exists() {
[ -n "$1" ] || die "Missing tag name"
[ -n "$(git for-each-ref --format='%(refname:short)' refs/tags/$1)" ]
}
#
# git_compare_refs()
#
# Tests whether two references have diverged and need merging
# first. It returns error codes to provide more detail, like so:
#
# 0 References point to the same commit
# 1 First given reference needs fast-forwarding
# 2 Second given reference needs fast-forwarding
# 3 References need a real merge
# 4 There is no merge base, i.e. the references have no common ancestors
#
git_compare_refs() {
local commit1 commit2 base
commit1=$(git rev-parse "$1"^{})
commit2=$(git rev-parse "$2"^{})
if [ "$commit1" != "$commit2" ]; then
base=$(git merge-base "$commit1" "$commit2")
if [ $? -ne 0 ]; then
return 4
elif [ "$commit1" = "$base" ]; then
return 1
elif [ "$commit2" = "$base" ]; then
return 2
else
return 3
fi
else
return 0
fi
}
#
# git_is_branch_merged_into()
#
# Checks whether branch $1 is successfully merged into $2
#
git_is_branch_merged_into() {
local merge_hash base_hash
merge_hash=$(git merge-base "$1"^{} "$2"^{})
base_hash=$(git rev-parse "$1"^{})
# If the hashes are equal, the branches are merged.
[ "$merge_hash" = "$base_hash" ]
}
#
# git_is_ancestor()
#
# This is the same function as git_is_branch_merged_into but
# for readability given a different name.
#
git_is_ancestor() {
git_is_branch_merged_into "$1" "$2"
}
#
# git_fetch_branch()
#
# $1 Origin - Where to fetch from
# $2 Branch - Which branch to fetch
#
# This fetches the given branch from the given origin.
# Instead of storing it in FETCH_HEAD it will be stored in
# refs/remotes/<origin>/<branch>
#
git_fetch_branch() {
local origin branch
[ -n "$1" ] || die "Missing origin"
[ -n "$2" ] || die "Missing branch name"
origin="$1"
branch="$2"
if git_remote_branch_exists "$origin/$branch"; then
git_do fetch -q "$origin" "$branch":refs/remotes/"$origin"/"$branch" || die "Could not fetch $branch from $origin."
else
warn "Trying to fetch branch '$origin/$branch' but it does not exist."
fi
}
#
# gitflow specific common functionality
#
# Function used to check if the repository is git-flow enabled.
gitflow_has_master_configured() {
local master
master=$(git config --get gitflow.branch.master)
[ "$master" != "" ] && git_local_branch_exists "$master"
}
gitflow_has_develop_configured() {
local develop
develop=$(git config --get gitflow.branch.develop)
[ "$develop" != "" ] && git_local_branch_exists "$develop"
}
gitflow_is_initialized() {
gitflow_has_master_configured && \
gitflow_has_develop_configured && \
[ "$(git config --get gitflow.branch.master)" != "$(git config --get gitflow.branch.develop)" ] && \
$(git config --get-regexp gitflow.prefix >/dev/null 2>&1)
}
# Loading settings that can be overridden using git config
gitflow_load_settings() {
export GIT_CURRENT_REPO_DIR="$(git rev-parse --show-toplevel 2>/dev/null)"
DOT_GIT_DIR=$(git rev-parse --git-dir)
export DOT_GIT_DIR="$(cd ${DOT_GIT_DIR} >/dev/null 2>&1 && pwd)"
export HOOKS_DIR="$(git config --get gitflow.path.hooks || echo ${DOT_GIT_DIR}/hooks)" # the second option is used to support previous versions of git-flow
export MASTER_BRANCH=$(git config --get gitflow.branch.master)
export DEVELOP_BRANCH=$(git config --get gitflow.branch.develop)
export ORIGIN=$(git config --get gitflow.origin || echo origin)
GITFLOW_CONFIG="$DOT_GIT_DIR/gitflow_config"
if [ -f "$GITFLOW_CONFIG" ]; then # move all settings from old .git/gitflow_config to the local conf.
warn "Migrating old \"$GITFLOW_CONFIG\" to the \"--local\" repo config."
_config_lines=`git config --list --file="$GITFLOW_CONFIG"`;
for _config_line in ${_config_lines}; do
_key=${_config_line%=*}
_value=${_config_line#=*}
git_do config --local gitflow.${_key} ${_value}
done;
mv "$GITFLOW_CONFIG" "$GITFLOW_CONFIG".backup 2>/dev/null
fi
}
#
# gitflow_resolve_nameprefix
#
# Inputs:
# $1 = name prefix to resolve
# $2 = branch prefix to use
#
# Searches branch names from git_local_branches() to look for a unique
# branch name whose name starts with the given name prefix.
#
# There are multiple exit codes possible:
# 0: The unambiguous full name of the branch is written to stdout
# (success)
# 1: No match is found.
# 2: Multiple matches found. These matches are written to stderr
#
gitflow_resolve_nameprefix() {
local name prefix
local match matches num_matches
name=$1
prefix=$2
# first, check if there is a perfect match
if git_local_branch_exists "$prefix$name"; then
echo "$name"
return 0
fi
matches=$(echo "$(git_local_branches)" | grep "^$(escape "$prefix$name")")
num_matches=$(echo "$matches" | wc -l)
if [ -z "$matches" ]; then
# no prefix match, so take it literally
warn "No branches match '$prefix$name*'"
return 1
else
if [ $num_matches -eq 1 ]; then
echo "${matches#$prefix}"
return 0
else
# multiple matches, cannot decide
warn "Multiple branches match prefix '$name':"
for match in $matches; do
warn "- $match"
done
return 2
fi
fi
}
#
# Check if the given branch is a git-flow branch
#
gitflow_is_prefixed_branch() {
local branch return
branch=$1
case $branch in
$(git config --get gitflow.prefix.feature)* | \
$(git config --get gitflow.prefix.bugfix)* | \
$(git config --get gitflow.prefix.release)* | \
$(git config --get gitflow.prefix.hotfix)* | \
$(git config --get gitflow.prefix.support)* )
return=0
;;
*)
return=1
;;
esac
return $return
}
#
# Update the config with the base of a new git-flow branch.
#
# @param $1 Base of the new branch
# @param $2 Name of the branch
#
gitflow_config_set_base_branch() {
local base branch
base=$1
branch=$2
$(git_do config --local "gitflow.branch.$branch.base" $base)
}
#
# Get the base of a branch as set by gitflow_set_branch
#
# @param $1 Name of the branch
# @return string|empty String when a base is found otherwise empty
#
gitflow_config_get_base_branch() {
local branch
branch=$1
echo $(git config --local --get "gitflow.branch.$branch.base")
}
#
# Remove the section that contains the base of a branch as set by gitflow_set_branch
#
# @param $1 Name of the branch
#
gitflow_config_remove_base_section() {
local branch
branch=$1
$(git_do config --local --remove-section "gitflow.branch.$branch" 2>/dev/null)
}
#
# Remove the base of the git-flow branch from the.
# @param $1 Name of the branch
#
gitflow_config_remove_base_branch() {
local base
base=$1
$(git_do config --local --unset "gitflow.branch.$branch.base" 2>/dev/null)
}
# gitflow_override_flag_boolean()
#
# Override a boolean flag
#
# Param $1: string The name of the config variable e.g. "feature.start.fetch"
# Param $2: string The flag name
#
gitflow_override_flag_boolean() {
local _variable
_variable=$(git config --bool --get gitflow.$1 2>&1)
case $? in
0)
[ "${_variable}" = "true" ] && eval "FLAGS_${2}=${FLAGS_TRUE}" || eval "FLAGS_${2}=${FLAGS_FALSE}"
;;
128)
die "${_variable}"
;;
esac
unset _variable
return ${FLAGS_TRUE}
}
# gitflow_override_flag_string()
#
# Override a string flag
#
# Param $1: string The name of the config variable e.g. "feature.start.fetch"
# Param $2: string The flag name
#
gitflow_override_flag_string() {
local _variable
_variable=$(git config --get gitflow.$1 2>&1)
case $? in
0)
eval "FLAGS_${2}=\"${_variable}\""
;;
esac
unset _variable
return ${FLAGS_TRUE}
}
# gitflow_create_squash_message()
#
# Create the squash message, overriding the one generated by git itself
#
# Param $1: string The line to be added
# Param $2: string The base of the branch that will me merged
# Param $3: string The branch that will be merged.
#
gitflow_create_squash_message() {
echo Squashed commit of the following:
echo
echo $1
echo
git log --no-merges --pretty=medium ^"$2" $3
}
#
# Parameter functions
#
gitflow_require_name_arg() {
if [ "$NAME" = "" ]; then
die_help "Missing argument <name>"
fi
}
gitflow_expand_nameprefix_arg() {
local expanded_name exitcode
gitflow_require_name_arg
expanded_name=$(gitflow_resolve_nameprefix "$NAME" "$PREFIX")
exitcode=$?
case $exitcode in
0)
NAME=$expanded_name
BRANCH=$PREFIX$NAME
;;
*)
exit 1
;;
esac
}
gitflow_require_version_arg() {
if [ "$VERSION" = "" ]; then
die_help "Missing argument <version>"
fi
}
gitflow_expand_versionprefix_arg() {
local expanded_version exitcode
gitflow_require_version_arg
version=$(gitflow_resolve_nameprefix "$VERSION" "$PREFIX")
exitcode=$?
case $exitcode in
0)
VERSION=$version
BRANCH=$PREFIX$VERSION
;;
*)
exit 1
;;
esac
}
gitflow_require_base_arg() {
if [ "$BASE" = "" ]; then
die_help "Missing argument <base>"
fi
}
gitflow_use_current_branch_name() {
local current_branch
current_branch=$(git_current_branch)
if startswith "$current_branch" "$PREFIX"; then
BRANCH=$current_branch
NAME=${BRANCH#$PREFIX}
else
warn "The current HEAD is no ${SUBCOMMAND} branch."
warn "Please specify a <name> argument."
exit 1
fi
}
gitflow_use_current_branch_version() {
local current_branch
current_branch=$(git_current_branch)
if startswith "$current_branch" "$PREFIX"; then
BRANCH=$current_branch
VERSION=${BRANCH#$PREFIX}
else
warn "The current HEAD is no ${SUBCOMMAND} branch."
warn "Please specify a <version> argument."
exit 1
fi
}
#
# Assertions for use in git-flow subcommands
#
require_git_repo() {
git rev-parse 2>/dev/null || die "Not a git repository"
}
require_gitflow_initialized() {
gitflow_is_initialized || die "Not a gitflow-enabled repo yet. Please run 'git flow init' first."
$(git config --get gitflow.prefix.versiontag >/dev/null 2>&1) || die "Version tag not set. Please run 'git flow init'."
}
require_clean_working_tree() {
local result
git_is_clean_working_tree
result=$?
if [ $result -eq 1 ]; then
die "Working tree contains unstaged changes. Aborting."
fi
if [ $result -eq 2 ]; then
die "Index contains uncommited changes. Aborting."
fi
}
require_base_is_local_branch() {
git_local_branch_exists "$1" || die "Base '$1' needs to be a branch. It does not exist and is required."
}
require_local_branch() {
git_local_branch_exists "$1" || die "Local branch '$1' does not exist and is required."
}
require_remote_branch() {
git_remote_branch_exists "$1" || die "Remote branch '$1' does not exist and is required."
}
require_branch() {
git_branch_exists "$1" || die "Branch '$1' does not exist and is required."
}
require_branch_absent() {
git_branch_exists "$1" && die "Branch '$1' already exists. Pick another name."
}
require_local_branch_absent() {
git_local_branch_exists "$1" && die "Branch '$1' already exists. Pick another name."
}
require_tag_absent() {
git_tag_exists "$1" && die "Tag '$1' already exists. Pick another name."
}
require_branches_equal() {
local compare_refs_result
require_local_branch "$1"
require_remote_branch "$2"
git_compare_refs "$1" "$2"
compare_refs_result=$?
if [ $compare_refs_result -gt 0 ]; then
warn "Branches '$1' and '$2' have diverged."
if [ $compare_refs_result -eq 1 ]; then
die "And branch '$1' may be fast-forwarded."
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
}
#
# Show commands if flag is set.
#
git_do() {
if flag showcommands; then
echo "git $@" >&2
fi
git "$@"
}
#
# run_filter_hook
#
# Looks for a Git hook script called as defined by the first variable
#
# filter-flow-command
#
# If such a hook script exists and is executable, it is called with the given
# positional arguments.
#
run_filter_hook() {
local command scriptfile return
command=$1
shift
scriptfile="${HOOKS_DIR}/filter-flow-${command}"
if [ -x "$scriptfile" ]; then
return=`$scriptfile "$@"`
if [ $? -eq 127 ]; then
echo "$return"
exit 127
fi
echo $return
else
echo "$@"
fi
}
#
# run_pre_hook
#
# Looks for a Git hook script called
#
# pre-flow-<subcmd>-<subaction>
#
# If such a hook script exists and is executable, it is called with the given
# positional arguments. If its return code non-zero, the git-flow action is
# aborted.
#
run_pre_hook() {
local scriptfile exitcode
scriptfile="${HOOKS_DIR}/pre-flow-${SUBCOMMAND}-${SUBACTION}"
exitcode=0
if [ -x "$scriptfile" ]; then
"$scriptfile" "$@"
exitcode=$?
if [ $exitcode -gt 0 ]; then
die "Hook command $scriptfile ended with exit code $exitcode."
fi
fi
}
#
# run_post_hook
#
# Looks for a Git hook script called
#
# post-flow-<subcmd>-<subaction>
#
# If such a hook script exists and is executable, it is called with the given
# positional arguments. Its return code is ignored.
#
run_post_hook() {
local scriptfile
scriptfile="${HOOKS_DIR}/post-flow-${SUBCOMMAND}-${SUBACTION}"
if [ -x "$scriptfile" ]; then
"$scriptfile" "$@"
fi
}
flags_help() {
eval "$( echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "-h" || echo exit $? )"
}
#!/bin/bash
# git-flow make-less installer for *nix systems, by Rick Osborne
# Based on the git-flow core Makefile:
# http://github.com/dreidev/gitflow/blob/master/Makefile
# Licensed under the same restrictions as git-flow:
# http://github.com/dreidev/gitflow/blob/develop/LICENSE
# Updated for the fork at petervanderdoes
usage() {
echo "Usage: [environment] gitflow-installer.sh [install|uninstall] [stable|develop]"
echo "Environment:"
echo " PREFIX=$PREFIX"
echo " REPO_HOME=$REPO_HOME"
echo " REPO_NAME=$REPO_NAME"
exit 1
}
# Does this need to be smarter for each host OS?
if [ -z "$PREFIX" ] ; then
PREFIX="/usr/local"
fi
if [ -z "$REPO_NAME" ] ; then
REPO_NAME="gitflow"
fi
if [ -z "$REPO_HOME" ] ; then
REPO_HOME="https://github.com/dreidev/gitflow.git"
fi
EXEC_PREFIX="$PREFIX"
BINDIR="$EXEC_PREFIX/bin"
DATAROOTDIR="$PREFIX/share"
DOCDIR="$DATAROOTDIR/doc/gitflow"
EXEC_FILES="git-flow"
SCRIPT_FILES="git-flow-init git-flow-feature git-flow-bugfix git-flow-hotfix git-flow-release git-flow-support git-flow-version gitflow-common gitflow-shFlags git-flow-config"
HOOK_FILES="$REPO_NAME/hooks/*"
echo "### git-flow no-make installer ###"
case "$1" in
uninstall)
echo "Uninstalling git-flow from $PREFIX"
if [ -d "$BINDIR" ] ; then
for script_file in $SCRIPT_FILES $EXEC_FILES ; do
echo "rm -vf $BINDIR/$script_file"
rm -vf "$BINDIR/$script_file"
done
rm -rf "$DOCDIR"
else
echo "The '$BINDIR' directory was not found."
fi
exit
;;
help)
usage
exit
;;
install)
if [ -z $2 ]; then
usage
exit
fi
echo "Installing git-flow to $BINDIR"
if [ -d "$REPO_NAME" -a -d "$REPO_NAME/.git" ] ; then
echo "Using existing repo: $REPO_NAME"
else
echo "Cloning repo from GitHub to $REPO_NAME"
git clone "$REPO_HOME" "$REPO_NAME"
fi
cd "$REPO_NAME"
git pull
cd "$OLDPWD"
case "$2" in
stable)
cd "$REPO_NAME"
git checkout master
cd "$OLDPWD"
;;
develop)
cd "$REPO_NAME"
git checkout develop
cd "$OLDPWD"
;;
*)
usage
exit
;;
esac
install -v -d -m 0755 "$PREFIX/bin"
install -v -d -m 0755 "$DOCDIR/hooks"
for exec_file in $EXEC_FILES ; do
install -v -m 0755 "$REPO_NAME/$exec_file" "$BINDIR"
done
for script_file in $SCRIPT_FILES ; do
install -v -m 0644 "$REPO_NAME/$script_file" "$BINDIR"
done
for hook_file in $HOOK_FILES ; do
install -v -m 0644 "$hook_file" "$DOCDIR/hooks"
done
exit
;;
*)
usage
exit
;;
esac
# $Id$
# vim:et:ft=sh:sts=2:sw=2
#
# Copyright 2008 Kate Ward. All Rights Reserved.
# Released under the LGPL (GNU Lesser General Public License)
#
# shFlags -- Advanced command-line flag library for Unix shell scripts.
# http://code.google.com/p/shflags/
#
# Author: kate.ward@forestent.com (Kate Ward)
#
# This module implements something like the google-gflags library available
# from http://code.google.com/p/google-gflags/.
#
# FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take
# a name, default value, help-string, and optional 'short' name (one-letter
# name). Some flags have other arguments, which are described with the flag.
#
# DEFINE_string: takes any input, and intreprets it as a string.
#
# DEFINE_boolean: does not take any arguments. Say --myflag to set
# FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false. For short
# flags, passing the flag on the command-line negates the default value, i.e.
# if the default is true, passing the flag sets the value to false.
#
# DEFINE_float: takes an input and intreprets it as a floating point number. As
# shell does not support floats per-se, the input is merely validated as
# being a valid floating point value.
#
# DEFINE_integer: takes an input and intreprets it as an integer.
#
# SPECIAL FLAGS: There are a few flags that have special meaning:
# --help (or -?) prints a list of all the flags in a human-readable fashion
# --flagfile=foo read flags from foo. (not implemented yet)
# -- as in getopt(), terminates flag-processing
#
# EXAMPLE USAGE:
#
# -- begin hello.sh --
# #! /bin/sh
# . ./shflags
# DEFINE_string name 'world' "somebody's name" n
# FLAGS "$@" || exit $?
# eval set -- "${FLAGS_ARGV}"
# echo "Hello, ${FLAGS_name}."
# -- end hello.sh --
#
# $ ./hello.sh -n Kate
# Hello, Kate.
#
# CUSTOMIZABLE BEHAVIOR:
#
# A script can override the default 'getopt' command by providing the path to
# an alternate implementation by defining the FLAGS_GETOPT_CMD variable.
#
# NOTES:
#
# * Not all systems include a getopt version that supports long flags. On these
# systems, only short flags are recognized.
#==============================================================================
# shFlags
#
# Shared attributes:
# flags_error: last error message
# flags_output: last function output (rarely valid)
# flags_return: last return value
#
# __flags_longNames: list of long names for all flags
# __flags_shortNames: list of short names for all flags
# __flags_boolNames: list of boolean flag names
#
# __flags_opts: options parsed by getopt
#
# Per-flag attributes:
# FLAGS_<flag_name>: contains value of flag named 'flag_name'
# __flags_<flag_name>_default: the default flag value
# __flags_<flag_name>_help: the flag help string
# __flags_<flag_name>_short: the flag short name
# __flags_<flag_name>_type: the flag type
#
# Notes:
# - lists of strings are space separated, and a null value is the '~' char.
# return if FLAGS already loaded
[ -n "${FLAGS_VERSION:-}" ] && return 0
FLAGS_VERSION='1.0.4pre'
# return values that scripts can use
FLAGS_TRUE=0
FLAGS_FALSE=1
FLAGS_ERROR=2
# determine some reasonable command defaults
__FLAGS_UNAME_S=`uname -s`
case "${__FLAGS_UNAME_S}" in
BSD) __FLAGS_EXPR_CMD='gexpr' ;;
*) __FLAGS_EXPR_CMD='expr' ;;
esac
# commands a user can override if needed
FLAGS_EXPR_CMD=${FLAGS_EXPR_CMD:-${__FLAGS_EXPR_CMD}}
FLAGS_GETOPT_CMD=${FLAGS_GETOPT_CMD:-getopt}
# specific shell checks
if [ -n "${ZSH_VERSION:-}" ]; then
setopt |grep "^shwordsplit$" >/dev/null
if [ $? -ne ${FLAGS_TRUE} ]; then
_flags_fatal 'zsh shwordsplit option is required for proper zsh operation'
fi
if [ -z "${FLAGS_PARENT:-}" ]; then
_flags_fatal "zsh does not pass \$0 through properly. please declare' \
\"FLAGS_PARENT=\$0\" before calling shFlags"
fi
fi
# can we use built-ins?
( echo "${FLAGS_TRUE#0}"; ) >/dev/null 2>&1
if [ $? -eq ${FLAGS_TRUE} ]; then
__FLAGS_USE_BUILTIN=${FLAGS_TRUE}
else
__FLAGS_USE_BUILTIN=${FLAGS_FALSE}
fi
#
# constants
#
# reserved flag names
__FLAGS_RESERVED_LIST=' ARGC ARGV ERROR FALSE GETOPT_CMD HELP PARENT TRUE '
__FLAGS_RESERVED_LIST="${__FLAGS_RESERVED_LIST} VERSION "
# getopt version
__FLAGS_GETOPT_VERS_STD=0
__FLAGS_GETOPT_VERS_ENH=1
__FLAGS_GETOPT_VERS_BSD=2
${FLAGS_GETOPT_CMD} >/dev/null 2>&1
case $? in
0) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} ;; # bsd getopt
1)
# Probably BusyBox. Getting a return of 4 with -T will confirm
${FLAGS_GETOPT_CMD} -T >/dev/null 2>&1
if [ "$?" == 4 ] ; then
__FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH}
else
_flags_fatal 'unable to determine getopt version'
fi
;;
2)
# TODO(kward): look into '-T' option to test the internal getopt() version
if [ "`${FLAGS_GETOPT_CMD} --version`" = '-- ' ]; then
__FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD}
else
__FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH}
fi
;;
*) _flags_fatal 'unable to determine getopt version' ;;
esac
# getopt optstring lengths
__FLAGS_OPTSTR_SHORT=0
__FLAGS_OPTSTR_LONG=1
__FLAGS_NULL='~'
# flag info strings
__FLAGS_INFO_DEFAULT='default'
__FLAGS_INFO_HELP='help'
__FLAGS_INFO_SHORT='short'
__FLAGS_INFO_TYPE='type'
# flag lengths
__FLAGS_LEN_SHORT=0
__FLAGS_LEN_LONG=1
# flag types
__FLAGS_TYPE_NONE=0
__FLAGS_TYPE_BOOLEAN=1
__FLAGS_TYPE_FLOAT=2
__FLAGS_TYPE_INTEGER=3
__FLAGS_TYPE_STRING=4
# set the constants readonly
__flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'`
for __flags_const in ${__flags_constants}; do
# skip certain flags
case ${__flags_const} in
FLAGS_HELP) continue ;;
FLAGS_PARENT) continue ;;
esac
# set flag readonly
if [ -z "${ZSH_VERSION:-}" ]; then
readonly ${__flags_const}
else # handle zsh
case ${ZSH_VERSION} in
[123].*) readonly ${__flags_const} ;;
*) readonly -g ${__flags_const} ;; # declare readonly constants globally
esac
fi
done
unset __flags_const __flags_constants
#
# internal variables
#
# space separated lists
__flags_boolNames=' ' # boolean flag names
__flags_longNames=' ' # long flag names
__flags_shortNames=' ' # short flag names
__flags_definedNames=' ' # defined flag names (used for validation)
__flags_nonegateNames=' '
__flags_columns='' # screen width in columns
__flags_opts='' # temporary storage for parsed getopt flags
#------------------------------------------------------------------------------
# private functions
#
# logging functions
_flags_debug() { echo "flags:DEBUG $@" >&2; }
_flags_warn() { echo "flags:WARN $@" >&2; }
_flags_error() { echo "flags:ERROR $@" >&2; }
_flags_fatal() { echo "flags:FATAL $@" >&2; exit ${FLAGS_ERROR}; }
# Define a flag.
#
# Calling this function will define the following info variables for the
# specified flag:
# FLAGS_flagname - the name for this flag (based upon the long flag name)
# __flags_<flag_name>_default - the default value
# __flags_flagname_help - the help string
# __flags_flagname_short - the single letter alias
# __flags_flagname_type - the type of flag (one of __FLAGS_TYPE_*)
#
# Args:
# _flags__type: integer: internal type of flag (__FLAGS_TYPE_*)
# _flags__name: string: long flag name
# _flags__default: default flag value
# _flags__help: string: help string
# _flags__short: string: (optional) short flag name
# Returns:
# integer: success of operation, or error
_flags_define()
{
if [ $# -lt 4 ]; then
flags_error='DEFINE error: too few arguments'
flags_return=${FLAGS_ERROR}
_flags_error "${flags_error}"
return ${flags_return}
fi
_flags_type_=$1
_flags_name_=$2
_flags_default_=$3
_flags_help_=$4
_flags_short_=${5:-${__FLAGS_NULL}}
_flags_return_=${FLAGS_TRUE}
_flags_usName_=`_flags_removeExclamationName ${_flags_name_}`
_flags_usName_=`_flags_underscoreName ${_flags_usName_}`
# check whether the flag name is reserved
_flags_itemInList ${_flags_usName_} "${__FLAGS_RESERVED_LIST}"
if [ $? -eq ${FLAGS_TRUE} ]; then
flags_error="flag name (${_flags_name_}) is reserved"
_flags_return_=${FLAGS_ERROR}
fi
# require short option for getopt that don't support long options
if [ ${_flags_return_} -eq ${FLAGS_TRUE} \
-a ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} \
-a "${_flags_short_}" = "${__FLAGS_NULL}" ]
then
flags_error="short flag required for (${_flags_name_}) on this platform"
_flags_return_=${FLAGS_ERROR}
fi
# check for existing long name definition
if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
if _flags_itemInList ${_flags_usName_} ${__flags_definedNames}; then
flags_error="definition for ([no]${_flags_name_}) already exists"
_flags_warn "${flags_error}"
_flags_return_=${FLAGS_FALSE}
fi
fi
# check for existing short name definition
if [ ${_flags_return_} -eq ${FLAGS_TRUE} \
-a "${_flags_short_}" != "${__FLAGS_NULL}" ]
then
if _flags_itemInList "${_flags_short_}" ${__flags_shortNames}; then
flags_error="flag short name (${_flags_short_}) already defined"
_flags_warn "${flags_error}"
_flags_return_=${FLAGS_FALSE}
fi
fi
# handle default value. note, on several occasions the 'if' portion of an
# if/then/else contains just a ':' which does nothing. a binary reversal via
# '!' is not done because it does not work on all shells.
if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
case ${_flags_type_} in
${__FLAGS_TYPE_BOOLEAN})
if _flags_validBool "${_flags_default_}"; then
case ${_flags_default_} in
true|t|0) _flags_default_=${FLAGS_TRUE} ;;
false|f|1) _flags_default_=${FLAGS_FALSE} ;;
esac
_flags_isNegate ${_flags_name_}
_flags_isNegate_=$?
else
flags_error="invalid default flag value '${_flags_default_}'"
_flags_return_=${FLAGS_ERROR}
fi
;;
${__FLAGS_TYPE_FLOAT})
if _flags_validFloat "${_flags_default_}"; then
:
else
flags_error="invalid default flag value '${_flags_default_}'"
_flags_return_=${FLAGS_ERROR}
fi
;;
${__FLAGS_TYPE_INTEGER})
if _flags_validInt "${_flags_default_}"; then
:
else
flags_error="invalid default flag value '${_flags_default_}'"
_flags_return_=${FLAGS_ERROR}
fi
;;
${__FLAGS_TYPE_STRING}) ;; # everything in shell is a valid string
*)
flags_error="unrecognized flag type '${_flags_type_}'"
_flags_return_=${FLAGS_ERROR}
;;
esac
fi
if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then
# store flag information
eval "FLAGS_${_flags_usName_}='${_flags_default_}'"
eval "__flags_${_flags_usName_}_${__FLAGS_INFO_TYPE}=${_flags_type_}"
eval "__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}=\
\"${_flags_default_}\""
eval "__flags_${_flags_usName_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\""
eval "__flags_${_flags_usName_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'"
# append flag names to name lists
__flags_shortNames="${__flags_shortNames}${_flags_short_} "
__flags_longNames="${__flags_longNames}`_flags_removeExclamationName ${_flags_name_}` "
if [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} \
-a ${_flags_isNegate_} -eq ${FLAGS_TRUE} ]; then
__flags_boolNames="${__flags_boolNames}no${_flags_name_} "
fi
# append flag names to defined names for later validation checks
__flags_definedNames="${__flags_definedNames}${_flags_usName_} "
if [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ]; then
if [ ${_flags_isNegate_} -eq ${FLAGS_TRUE} ]; then
__flags_definedNames="${__flags_definedNames}no${_flags_usName_} "
fi
fi
# append flag names to nonegateNames names for later validation checks
__flags_definedNames="${__flags_definedNames}${_flags_usName_} "
if [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ]; then
if [ ${_flags_isNegate_} -eq ${FLAGS_FALSE} ]; then
__flags_nonegateNames="${__flags_nonegateNames}`_flags_removeExclamationName ${_flags_name_}` "
fi
fi
fi
flags_return=${_flags_return_}
unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ \
_flags_short_ _flags_type_ _flags_usName_
[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
return ${flags_return}
}
# Underscore a flag name by replacing dashes with underscores.
#
# Args:
# unnamed: string: log flag name
# Output:
# string: underscored name
_flags_underscoreName()
{
echo $1 |tr '-' '_'
}
# Strip potential exclamation mark
#
# Args:
# unnamed: string: log flag name
# Output:
# string: exclamation stripped from name
_flags_removeExclamationName()
{
_flags_opt_=$1
if _flags_isNegate "${_flags_opt_}"; then
echo ${_flags_opt_}
else
if _flags_useBuiltin; then
echo ${_flags_opt_%!*}
else
echo ${_flags_opt_}|sed 's/!$//'
fi
fi
unset _flags_opt_
return ${FLAGS_TRUE}
}
# Check if a flag ends in an exclamation mark,
# if it does, there will not be a negate option
# Args:
# unnamed: string: flag name
# return:
# boolean
_flags_isNegate()
{
case $1 in
*!) flags_return=${FLAGS_FALSE} ;;
*) flags_return=${FLAGS_TRUE} ;;
esac
return ${flags_return}
}
# Return valid getopt options using currently defined list of long options.
#
# This function builds a proper getopt option string for short (and long)
# options, using the current list of long options for reference.
#
# Args:
# _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*)
# Output:
# string: generated option string for getopt
# Returns:
# boolean: success of operation (always returns True)
_flags_genOptStr()
{
_flags_optStrType_=$1
_flags_opts_=''
for _flags_name_ in ${__flags_longNames}; do
_flags_usName_=`_flags_removeExclamationName ${_flags_name_}`
_flags_usName_=`_flags_underscoreName ${_flags_usName_}`
_flags_type_=`_flags_getFlagInfo ${_flags_usName_} ${__FLAGS_INFO_TYPE}`
[ $? -eq ${FLAGS_TRUE} ] || _flags_fatal 'call to _flags_type_ failed'
case ${_flags_optStrType_} in
${__FLAGS_OPTSTR_SHORT})
_flags_shortName_=`_flags_getFlagInfo \
${_flags_usName_} ${__FLAGS_INFO_SHORT}`
if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then
_flags_opts_="${_flags_opts_}${_flags_shortName_}"
# getopt needs a trailing ':' to indicate a required argument
[ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \
_flags_opts_="${_flags_opts_}:"
fi
;;
${__FLAGS_OPTSTR_LONG})
_flags_opts_="${_flags_opts_:+${_flags_opts_},}`_flags_removeExclamationName ${_flags_name_}`"
# getopt needs a trailing ':' to indicate a required argument
[ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \
_flags_opts_="${_flags_opts_}:"
;;
esac
done
echo "${_flags_opts_}"
unset _flags_name_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \
_flags_type_ _flags_usName_
return ${FLAGS_TRUE}
}
# Returns flag details based on a flag name and flag info.
#
# Args:
# string: underscored flag name
# string: flag info (see the _flags_define function for valid info types)
# Output:
# string: value of dereferenced flag variable
# Returns:
# integer: one of FLAGS_{TRUE|FALSE|ERROR}
_flags_getFlagInfo()
{
# note: adding gFI to variable names to prevent naming conflicts with calling
# functions
_flags_gFI_usName_=$1
_flags_gFI_info_=$2
_flags_infoVar_="__flags_${_flags_gFI_usName_}_${_flags_gFI_info_}"
_flags_strToEval_="_flags_infoValue_=\"\${${_flags_infoVar_}:-}\""
eval "${_flags_strToEval_}"
if [ -n "${_flags_infoValue_}" ]; then
flags_return=${FLAGS_TRUE}
else
# see if the _flags_gFI_usName_ variable is a string as strings can be
# empty...
# note: the DRY principle would say to have this function call itself for
# the next three lines, but doing so results in an infinite loop as an
# invalid _flags_name_ will also not have the associated _type variable.
# Because it doesn't (it will evaluate to an empty string) the logic will
# try to find the _type variable of the _type variable, and so on. Not so
# good ;-)
_flags_typeVar_="__flags_${_flags_gFI_usName_}_${__FLAGS_INFO_TYPE}"
_flags_strToEval_="_flags_typeValue_=\"\${${_flags_typeVar_}:-}\""
eval "${_flags_strToEval_}"
if [ "${_flags_typeValue_}" = "${__FLAGS_TYPE_STRING}" ]; then
flags_return=${FLAGS_TRUE}
else
flags_return=${FLAGS_ERROR}
flags_error="missing flag info variable (${_flags_infoVar_})"
fi
fi
echo "${_flags_infoValue_}"
unset _flags_gFI_usName_ _flags_gfI_info_ _flags_infoValue_ _flags_infoVar_ \
_flags_strToEval_ _flags_typeValue_ _flags_typeVar_
[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}"
return ${flags_return}
}
# Check for presense of item in a list.
#
# Passed a string (e.g. 'abc'), this function will determine if the string is
# present in the list of strings (e.g. ' foo bar abc ').
#
# Args:
# _flags_str_: string: string to search for in a list of strings
# unnamed: list: list of strings
# Returns:
# boolean: true if item is in the list
_flags_itemInList() {
_flags_str_=$1
shift
_flags_list_=" ${*:-} "
case ${_flags_list_} in
*\ ${_flags_str_}\ *)
flags_return=$FLAGS_TRUE
;;
*)
flags_return=$FLAGS_FALSE
;;
esac
unset _flags_str_ _flags_list_
return ${flags_return}
}
# Returns the width of the current screen.
#
# Output:
# integer: width in columns of the current screen.
_flags_columns()
{
if [ -z "${__flags_columns}" ]; then
# determine the value and store it
if eval stty size >/dev/null 2>&1; then
# stty size worked :-)
set -- `stty size`
__flags_columns=$2
elif eval tput cols >/dev/null 2>&1; then
set -- `tput cols`
__flags_columns=$1
else
__flags_columns=80 # default terminal width
fi
fi
echo ${__flags_columns}
}
# Validate a boolean.
#
# Args:
# _flags__bool: boolean: value to validate
# Returns:
# bool: true if the value is a valid boolean
_flags_validBool()
{
_flags_bool_=$1
flags_return=${FLAGS_TRUE}
case "${_flags_bool_}" in
true|t|0) ;;
false|f|1) ;;
*) flags_return=${FLAGS_FALSE} ;;
esac
unset _flags_bool_
return ${flags_return}
}
# Validate a float.
#
# Args:
# _flags_float_: float: value to validate
# Returns:
# bool: true if the value is a valid integer
_flags_validFloat()
{
flags_return=${FLAGS_FALSE}
[ -n "$1" ] || return ${flags_return}
_flags_float_=$1
if _flags_validInt ${_flags_float_}; then
flags_return=${FLAGS_TRUE}
elif _flags_useBuiltin; then
_flags_float_whole_=${_flags_float_%.*}
_flags_float_fraction_=${_flags_float_#*.}
if _flags_validInt ${_flags_float_whole_:-0} -a \
_flags_validInt ${_flags_float_fraction_}; then
flags_return=${FLAGS_TRUE}
fi
unset _flags_float_whole_ _flags_float_fraction_
else
flags_return=${FLAGS_TRUE}
case ${_flags_float_} in
-*) # negative floats
_flags_test_=`${FLAGS_EXPR_CMD} -- "${_flags_float_}" :\
'\(-[0-9]*\.[0-9]*\)'`
;;
*) # positive floats
_flags_test_=`${FLAGS_EXPR_CMD} -- "${_flags_float_}" :\
'\([0-9]*\.[0-9]*\)'`
;;
esac
[ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE}
unset _flags_test_
fi
unset _flags_float_ _flags_float_whole_ _flags_float_fraction_
return ${flags_return}
}
# Validate an integer.
#
# Args:
# _flags_int_: integer: value to validate
# Returns:
# bool: true if the value is a valid integer
_flags_validInt()
{
flags_return=${FLAGS_FALSE}
[ -n "$1" ] || return ${flags_return}
_flags_int_=$1
case ${_flags_int_} in
-*.*) ;; # ignore negative floats (we'll invalidate them later)
-*) # strip possible leading negative sign
if _flags_useBuiltin; then
_flags_int_=${_flags_int_#-}
else
_flags_int_=`${FLAGS_EXPR_CMD} -- "${_flags_int_}" : '-\([0-9][0-9]*\)'`
fi
;;
esac
case ${_flags_int_} in
*[!0-9]*) flags_return=${FLAGS_FALSE} ;;
*) flags_return=${FLAGS_TRUE} ;;
esac
unset _flags_int_
return ${flags_return}
}
# Parse command-line options using the standard getopt.
#
# Note: the flag options are passed around in the global __flags_opts so that
# the formatting is not lost due to shell parsing and such.
#
# Args:
# @: varies: command-line options to parse
# Returns:
# integer: a FLAGS success condition
_flags_getoptStandard()
{
flags_return=${FLAGS_TRUE}
_flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
# check for spaces in passed options
for _flags_opt_ in "$@"; do
# note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
_flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'`
if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then
flags_error='the available getopt does not support spaces in options'
flags_return=${FLAGS_ERROR}
break
fi
done
if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
__flags_opts=`getopt ${_flags_shortOpts_} $@ 2>&1`
_flags_rtrn_=$?
if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then
_flags_warn "${__flags_opts}"
flags_error='unable to parse provided options with getopt.'
flags_return=${FLAGS_ERROR}
fi
fi
unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_
return ${flags_return}
}
# Parse command-line options using the enhanced getopt.
#
# Note: the flag options are passed around in the global __flags_opts so that
# the formatting is not lost due to shell parsing and such.
#
# Args:
# @: varies: command-line options to parse
# Returns:
# integer: a FLAGS success condition
_flags_getoptEnhanced()
{
flags_return=${FLAGS_TRUE}
_flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}`
_flags_boolOpts_=`echo "${__flags_boolNames}" \
|sed 's/^ *//;s/ *$//;s/ /,/g'`
_flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}`
__flags_opts=`${FLAGS_GETOPT_CMD} \
-o ${_flags_shortOpts_} \
-l "${_flags_longOpts_},${_flags_boolOpts_}" \
-- "$@" 2>&1`
_flags_rtrn_=$?
if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then
_flags_warn "${__flags_opts}"
flags_error='unable to parse provided options with getopt.'
flags_return=${FLAGS_ERROR}
fi
unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_
return ${flags_return}
}
# Dynamically parse a getopt result and set appropriate variables.
#
# This function does the actual conversion of getopt output and runs it through
# the standard case structure for parsing. The case structure is actually quite
# dynamic to support any number of flags.
#
# Args:
# argc: int: original command-line argument count
# @: varies: output from getopt parsing
# Returns:
# integer: a FLAGS success condition
_flags_parseGetopt()
{
_flags_argc_=$1
shift
flags_return=${FLAGS_TRUE}
if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
set -- $@
else
# note the quotes around the `$@' -- they are essential!
eval set -- "$@"
fi
# Provide user with the number of arguments to shift by later.
# NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not
# properly give user access to non-flag arguments mixed in between flag
# arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only
# for backwards compatibility reasons.
FLAGS_ARGC=`_flags_math "$# - 1 - ${_flags_argc_}"`
# handle options. note options with values must do an additional shift
while true; do
_flags_opt_=$1
_flags_arg_=${2:-}
_flags_type_=${__FLAGS_TYPE_NONE}
_flags_name_=''
# determine long flag name
case "${_flags_opt_}" in
--) shift; break ;; # discontinue option parsing
--*) # long option
if _flags_useBuiltin; then
_flags_opt_=${_flags_opt_#*--}
else
_flags_opt_=`${FLAGS_EXPR_CMD} -- "${_flags_opt_}" : '--\(.*\)'`
fi
_flags_len_=${__FLAGS_LEN_LONG}
if _flags_itemInList "${_flags_opt_}" ${__flags_longNames}; then
_flags_name_=${_flags_opt_}
else
# check for negated long boolean version
if _flags_itemInList "${_flags_opt_}" ${__flags_boolNames}; then
if _flags_useBuiltin; then
_flags_name_=${_flags_opt_#*no}
else
_flags_name_=`${FLAGS_EXPR_CMD} -- "${_flags_opt_}" : 'no\(.*\)'`
fi
_flags_type_=${__FLAGS_TYPE_BOOLEAN}
_flags_arg_=${__FLAGS_NULL}
fi
fi
;;
-*) # short option
if _flags_useBuiltin; then
_flags_opt_=${_flags_opt_#*-}
else
_flags_opt_=`${FLAGS_EXPR_CMD} -- "${_flags_opt_}" : '-\(.*\)'`
fi
_flags_len_=${__FLAGS_LEN_SHORT}
if _flags_itemInList "${_flags_opt_}" ${__flags_shortNames}; then
# yes. match short name to long name. note purposeful off-by-one
# (too high) with awk calculations.
_flags_pos_=`echo "${__flags_shortNames}" \
|awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \
e=${_flags_opt_}`
_flags_name_=`echo "${__flags_longNames}" \
|awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"`
fi
;;
esac
# die if the flag was unrecognized
if [ -z "${_flags_name_}" ]; then
flags_error="unrecognized option (${_flags_opt_})"
flags_return=${FLAGS_ERROR}
break
fi
# set new flag value
_flags_usName_=`_flags_removeExclamationName ${_flags_name_}`
_flags_usName_=`_flags_underscoreName ${_flags_usName_}`
[ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \
_flags_type_=`_flags_getFlagInfo \
"${_flags_usName_}" ${__FLAGS_INFO_TYPE}`
case ${_flags_type_} in
${__FLAGS_TYPE_BOOLEAN})
if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then
if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then
eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}"
else
eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}"
fi
else
_flags_strToEval_="_flags_val_=\
\${__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}}"
eval "${_flags_strToEval_}"
if [ ${_flags_val_} -eq ${FLAGS_FALSE} ]; then
eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}"
else
eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}"
fi
fi
;;
${__FLAGS_TYPE_FLOAT})
if _flags_validFloat "${_flags_arg_}"; then
eval "FLAGS_${_flags_usName_}='${_flags_arg_}'"
else
flags_error="invalid float value (${_flags_arg_})"
flags_return=${FLAGS_ERROR}
break
fi
;;
${__FLAGS_TYPE_INTEGER})
if _flags_validInt "${_flags_arg_}"; then
eval "FLAGS_${_flags_usName_}='${_flags_arg_}'"
else
flags_error="invalid integer value (${_flags_arg_})"
flags_return=${FLAGS_ERROR}
break
fi
;;
${__FLAGS_TYPE_STRING})
eval "FLAGS_${_flags_usName_}='${_flags_arg_}'"
;;
esac
# handle special case help flag
if [ "${_flags_usName_}" = 'help' ]; then
if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then
flags_help
flags_error='help requested'
flags_return=${FLAGS_TRUE}
break
fi
fi
# shift the option and non-boolean arguements out.
shift
[ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ] && shift
done
# give user back non-flag arguments
FLAGS_ARGV=''
while [ $# -gt 0 ]; do
FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'"
shift
done
unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \
_flags_strToEval_ _flags_type_ _flags_usName_ _flags_val_
return ${flags_return}
}
# Perform some path using built-ins.
#
# Args:
# $@: string: math expression to evaluate
# Output:
# integer: the result
# Returns:
# bool: success of math evaluation
_flags_math()
{
if [ $# -eq 0 ]; then
flags_return=${FLAGS_FALSE}
elif _flags_useBuiltin; then
# Variable assignment is needed as workaround for Solaris Bourne shell,
# which cannot parse a bare $((expression)).
_flags_expr_='$(($@))'
eval echo ${_flags_expr_}
flags_return=$?
unset _flags_expr_
else
eval expr $@
flags_return=$?
fi
return ${flags_return}
}
# Cross-platform strlen() implementation.
#
# Args:
# _flags_str: string: to determine length of
# Output:
# integer: length of string
# Returns:
# bool: success of strlen evaluation
_flags_strlen()
{
_flags_str_=${1:-}
if [ -z "${_flags_str_}" ]; then
flags_output=0
elif _flags_useBuiltin; then
flags_output=${#_flags_str_}
else
flags_output=`${FLAGS_EXPR_CMD} -- "${_flags_str_}" : '.*'`
fi
flags_return=$?
unset _flags_str_
echo ${flags_output}
return ${flags_return}
}
# Use built-in helper function to enable unit testing.
#
# Args:
# None
# Returns:
# bool: true if built-ins should be used
_flags_useBuiltin()
{
return ${__FLAGS_USE_BUILTIN}
}
#------------------------------------------------------------------------------
# public functions
#
# A basic boolean flag. Boolean flags do not take any arguments, and their
# value is either 1 (false) or 0 (true). For long flags, the false value is
# specified on the command line by prepending the word 'no'. With short flags,
# the presense of the flag toggles the current value between true and false.
# Specifying a short boolean flag twice on the command results in returning the
# value back to the default value.
#
# A default value is required for boolean flags.
#
# For example, lets say a Boolean flag was created whose long name was 'update'
# and whose short name was 'x', and the default value was 'false'. This flag
# could be explicitly set to 'true' with '--update' or by '-x', and it could be
# explicitly set to 'false' with '--noupdate'.
DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; }
# Other basic flags.
DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; }
DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; }
DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; }
# Parse the flags.
#
# Args:
# unnamed: list: command-line flags to parse
# Returns:
# integer: success of operation, or error
FLAGS()
{
# define a standard 'help' flag if one isn't already defined
[ -z "${__flags_help_type:-}" ] && \
DEFINE_boolean 'help!' false 'show this help' 'h'
# parse options
if [ $# -gt 0 ]; then
if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then
_flags_getoptStandard "$@"
else
_flags_getoptEnhanced "$@"
fi
flags_return=$?
else
# nothing passed; won't bother running getopt
__flags_opts='--'
flags_return=${FLAGS_TRUE}
fi
if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then
_flags_parseGetopt $# "${__flags_opts}"
flags_return=$?
fi
[ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}"
return ${flags_return}
}
# This is a helper function for determining the 'getopt' version for platforms
# where the detection isn't working. It simply outputs debug information that
# can be included in a bug report.
#
# Args:
# none
# Output:
# debug info that can be included in a bug report
# Returns:
# nothing
flags_getoptInfo()
{
# platform info
_flags_debug "uname -a: `uname -a`"
_flags_debug "PATH: ${PATH}"
# shell info
if [ -n "${BASH_VERSION:-}" ]; then
_flags_debug 'shell: bash'
_flags_debug "BASH_VERSION: ${BASH_VERSION}"
elif [ -n "${ZSH_VERSION:-}" ]; then
_flags_debug 'shell: zsh'
_flags_debug "ZSH_VERSION: ${ZSH_VERSION}"
fi
# getopt info
${FLAGS_GETOPT_CMD} >/dev/null
_flags_getoptReturn=$?
_flags_debug "getopt return: ${_flags_getoptReturn}"
_flags_debug "getopt --version: `${FLAGS_GETOPT_CMD} --version 2>&1`"
unset _flags_getoptReturn
}
# Returns whether the detected getopt version is the enhanced version.
#
# Args:
# none
# Output:
# none
# Returns:
# bool: true if getopt is the enhanced version
flags_getoptIsEnh()
{
test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH}
}
# Returns whether the detected getopt version is the standard version.
#
# Args:
# none
# Returns:
# bool: true if getopt is the standard version
flags_getoptIsStd()
{
test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD}
}
# This is effectively a 'usage()' function. It prints usage information and
# exits the program with ${FLAGS_FALSE} if it is ever found in the command line
# arguments. Note this function can be overridden so other apps can define
# their own --help flag, replacing this one, if they want.
#
# Args:
# none
# Returns:
# integer: success of operation (always returns true)
flags_help()
{
if [ -n "${FLAGS_HELP:-}" ]; then
echo "${FLAGS_HELP}" >&2
else
echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2
fi
if [ -n "${__flags_longNames}" ]; then
echo 'flags:' >&2
for flags_name_ in ${__flags_longNames}; do
flags_flagStr_=''
flags_boolStr_=''
flags_usName_=`_flags_underscoreName ${flags_name_}`
flags_default_=`_flags_getFlagInfo \
"${flags_usName_}" ${__FLAGS_INFO_DEFAULT}`
flags_help_=`_flags_getFlagInfo \
"${flags_usName_}" ${__FLAGS_INFO_HELP}`
flags_short_=`_flags_getFlagInfo \
"${flags_usName_}" ${__FLAGS_INFO_SHORT}`
flags_type_=`_flags_getFlagInfo \
"${flags_usName_}" ${__FLAGS_INFO_TYPE}`
[ "${flags_short_}" != "${__FLAGS_NULL}" ] && \
flags_flagStr_="-${flags_short_}"
if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then
[ "${flags_short_}" != "${__FLAGS_NULL}" ] && \
flags_flagStr_="${flags_flagStr_},"
# add [no] to long boolean flag names, except the 'help' flag
if [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ]; then
_flags_itemInList "${flags_name_}" ${__flags_nonegateNames}
if [ $? -eq ${FLAGS_FALSE} ]; then
flags_boolStr_='[no]'
fi
fi
flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:"
fi
case ${flags_type_} in
${__FLAGS_TYPE_BOOLEAN})
if [ ${flags_default_} -eq ${FLAGS_TRUE} ]; then
flags_defaultStr_='true'
else
flags_defaultStr_='false'
fi
;;
${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER})
flags_defaultStr_=${flags_default_} ;;
${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;;
esac
flags_defaultStr_="(default: ${flags_defaultStr_})"
flags_helpStr_=" ${flags_flagStr_} ${flags_help_} ${flags_defaultStr_}"
_flags_strlen "${flags_helpStr_}" >/dev/null
flags_helpStrLen_=${flags_output}
flags_columns_=`_flags_columns`
if [ ${flags_helpStrLen_} -lt ${flags_columns_} ]; then
echo "${flags_helpStr_}" >&2
else
echo " ${flags_flagStr_} ${flags_help_}" >&2
# note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06
# because it doesn't like empty strings when used in this manner.
flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \
|awk '{printf "%"length($0)-2"s", ""}'`"
flags_helpStr_=" ${flags_emptyStr_} ${flags_defaultStr_}"
_flags_strlen "${flags_helpStr_}" >/dev/null
flags_helpStrLen_=${flags_output}
if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} \
-o ${flags_helpStrLen_} -lt ${flags_columns_} ]; then
# indented to match help string
echo "${flags_helpStr_}" >&2
else
# indented four from left to allow for longer defaults as long flag
# names might be used too, making things too long
echo " ${flags_defaultStr_}" >&2
fi
fi
done
fi
unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ \
flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \
flags_columns_ flags_short_ flags_type_ flags_usName_
return ${FLAGS_TRUE}
}
# Reset shflags back to an uninitialized state.
#
# Args:
# none
# Returns:
# nothing
flags_reset()
{
for flags_name_ in ${__flags_longNames}; do
flags_usName_=`_flags_removeExclamationName ${flags_name_}`
flags_usName_=`_flags_underscoreName ${flags_usName_}`
flags_strToEval_="unset FLAGS_${flags_usName_}"
for flags_type_ in \
${__FLAGS_INFO_DEFAULT} \
${__FLAGS_INFO_HELP} \
${__FLAGS_INFO_SHORT} \
${__FLAGS_INFO_TYPE}
do
flags_strToEval_=\
"${flags_strToEval_} __flags_${flags_usName_}_${flags_type_}"
done
eval ${flags_strToEval_}
done
# reset internal variables
__flags_boolNames=' '
__flags_longNames=' '
__flags_shortNames=' '
__flags_definedNames=' '
unset flags_name_ flags_type_ flags_strToEval_ flags_usName_
}
#!/bin/sh
#
# Runs during git flow hotfix finish and a tag message is given
#
# Positional arguments:
# $1 Message
# $2 Full version
#
# Return MESSAGE
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
MESSAGE="$1"
# Implement your script here.
# Return the MESSAGE
echo "${MESSAGE}"
exit 0
#!/bin/sh
#
# Runs during git flow hotfix start
#
# Positional arguments:
# $1 Version
#
# Return VERSION - When VERSION is returned empty, git-flow will stop as the
# version is necessary
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
VERSION=$1
# Implement your script here.
# Return the VERSION
echo ${VERSION}
exit 0
#!/bin/sh
#
# Runs during git flow release branch and a tag message is given
#
# Positional arguments:
# $1 Message
# $2 Full version
#
# Return MESSAGE
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
MESSAGE="$1"
# Implement your script here.
# Return the MESSAGE
echo "${MESSAGE}"
exit 0
#!/bin/sh
#
# Runs during git flow release finish and a tag message is given
#
# Positional arguments:
# $1 Message
# $2 Full version
#
# Return MESSAGE
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
MESSAGE="$1"
# Implement your script here.
# Return the MESSAGE
echo "${MESSAGE}"
exit 0
#!/bin/sh
#
# Runs during git flow release start
#
# Positional arguments:
# $1 Version
#
# Return VERSION - When VERSION is returned empty, git-flow will stop as the
# version is necessary
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
# Implement your script here.
# Return the VERSION
echo ${VERSION}
exit 0
#!/bin/sh
#
# Runs at the end of git flow bugfix delete
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the bugfix prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow bugfix finish
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the bugfix prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow bugfix publish
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the bugfix prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow bugfix pull.
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The remote to pull from
# $3 The full branch name (including the bugfix prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
REMOTE=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow bugfix start
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the bugfix prefix)
# $4 The base from which this bugfix is started
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
BASE=$4
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow bugfix track
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the bugfix prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow feature delete
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow feature finish
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow feature publish
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow feature pull.
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The remote to pull from
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
REMOTE=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow feature start
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
# $4 The base from which this feature is started
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
BASE=$4
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow feature track
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow hotfix delete
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow hotfix finish
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow hotfix publish
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow hotfix start
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
# $4 The base from which this feature is started
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
BASE=$4
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow release branch
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow release delete
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow release finish
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow release publish
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow release start
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the release prefix)
# $4 The base from which this release is started
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
BASE=$4
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs at the end of git flow release track
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
exit 0
#!/bin/sh
#
# Runs before git flow feature delete
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow feature finish
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow feature publish
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow feature pull.
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The remote to pull from
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
REMOTE=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow feature start
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
# $4 The base from which this feature is started
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
BASE=$4
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow feature track
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
NAME=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow hotfix delete
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow hotfix finish
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow hotfix publish
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow hotfix start
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the feature prefix)
# $4 The base from which this feature is started
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
BASE=$4
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow release branch
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow release delete
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow release finish
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow release publish
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow release start
#
# Positional arguments:
# $1 The version (including the version prefix)
# $2 The origin remote
# $3 The full branch name (including the release prefix)
# $4 The base from which this release is started
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
BASE=$4
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
#!/bin/sh
#
# Runs before git flow release track
#
# Positional arguments:
# $1 The friendly name of the branch
# $2 The origin remote
# $3 The full branch name (including the release prefix)
#
# The following variables are available as they are exported by git-flow:
#
# MASTER_BRANCH - The branch defined as Master
# DEVELOP_BRANCH - The branch defined as Develop
#
VERSION=$1
ORIGIN=$2
BRANCH=$3
# Implement your script here.
# To terminate the git-flow action, return a non-zero exit code.
exit 0
...@@ -3,15 +3,11 @@ ...@@ -3,15 +3,11 @@
"version": "0.4.11", "version": "0.4.11",
"description": "Modified gitflow for dreidev", "description": "Modified gitflow for dreidev",
"main": "src/index.js", "main": "src/index.js",
"scripts": {
"postinstall": "curl https://raw.githubusercontent.com/dreidev/gitflow/develop/contrib/gitflow-installer.sh > gitflow-installer.sh; chmod a+x gitflow-installer.sh; sudo bash gitflow-installer.sh install stable",
"postuninstall": "curl https://raw.githubusercontent.com/dreidev/gitflow/develop/contrib/gitflow-installer.sh > gitflow-installer.sh; chmod a+x gitflow-installer.sh; sudo bash gitflow-installer.sh uninstall"
},
"files": [ "files": [
"src/" "src/"
], ],
"bin": { "bin": {
"flow": "src/flow.js" "flow": "./src/flow.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
...@@ -31,14 +27,40 @@ ...@@ -31,14 +27,40 @@
"email": "clive@makamara.me", "email": "clive@makamara.me",
"url": "http://github.com/cmosh", "url": "http://github.com/cmosh",
"organization": "dreidev" "organization": "dreidev"
}, },
"license": "LGPL", "license": "LGPL",
"bugs": { "bugs": {
"url": "https://github.com/dreidev/gitflow/issues" "url": "https://github.com/dreidev/gitflow/issues"
}, },
"homepage": "https://github.com/dreidev/gitflow#readme", "homepage": "https://github.com/dreidev/gitflow#readme",
"dependencies": { "dependencies": {
"babel": "^6.5.2",
"camo": "^0.12.3",
"chalk": "^1.1.3",
"commander": "^2.9.0", "commander": "^2.9.0",
"shelljs": "^0.7.6" "mongoose": "^4.8.2",
} "nedb": "^1.8.0",
"nodegit": "^0.17.0",
"shelljs": "^0.7.6",
"tingodb": "^0.5.1",
"tungus": "0.0.5",
"vorpal": "^1.11.4"
},
"nexe": {
"input": "./src/flow.js",
"output": "flow^$",
"temp": "build",
"browserify": {
"requires": [],
"excludes": [],
"paths": []
},
"runtime": {
"framework": "node",
"version": "6.9.1",
"js-flags": "--use_strict",
"ignoreFlags": true
}
}
} }
module.exports = function(args, callback) {
this.log('bugfix');
callback();
};
\ No newline at end of file
module.exports = function(args, callback) {
this.log('feature');
callback();
};
\ No newline at end of file
require('shelljs/global');
const program = require('commander');
program.parse(process.argv);
var args = program.args.toString().replace(',',' ');
if (!which('git')) {
echo('Sorry, this script requires git');
exit(1);
}
exec('git flow bugfix '+args,{silent:true}, function(code, stdout, stderr) {
console.log(stdout.replace('git ',''));
console.log(stderr);
});
require('shelljs/global');
const program = require('commander');
program.parse(process.argv);
var args = program.args.toString().replace(',',' ');
if (!which('git')) {
echo('Sorry, this script requires git');
exit(1);
}
exec('git flow feature '+args,{silent:true}, function(code, stdout, stderr) {
console.log(stdout.replace("git ",""));
console.log(stderr);
});
require('shelljs/global');
const program = require('commander');
program.parse(process.argv);
var args = program.args.toString().replace(',',' ');
if (!which('git')) {
echo('Sorry, this script requires git');
exit(1);
}
exec('git flow hotfix '+args,{silent:true}, function(code, stdout, stderr) {
console.log(stdout.replace("git ",""));
console.log(stderr);
});
require('shelljs/global');
const program = require('commander');
program.parse(process.argv);
var args = program.args.toString().replace(',',' ');
if (!which('git')) {
echo('Sorry, this script requires git');
exit(1);
}
exec('git flow init '+args,{silent:true}, function(code, stdout, stderr) {
console.log(stdout.replace("git ",""));
console.log(stderr);
});
require('shelljs/global');
const program = require('commander');
program.parse(process.argv);
var args = program.args.toString().replace(',',' ');
if (!which('git')) {
echo('Sorry, this script requires git');
exit(1);
}
exec('git flow release '+args,{silent:true}, function(code, stdout, stderr) {
console.log(stdout.replace("git ",""));
console.log(stderr);
});
require('shelljs/global');
const program = require('commander');
program.parse(process.argv);
var args = program.args.toString().replace(',',' ');
if (!which('git')) {
echo('Sorry, this script requires git');
exit(1);
}
exec('git flow support '+args,{silent:true}, function(code, stdout, stderr) {
console.log(stdout.replace("git ",""));
console.log(stderr);
});
#! /usr/bin/env node #! /usr/bin/env node
'use strict'; 'use strict';
const program = require('commander');
const version = require('../package.json').version; var vorpal = require('vorpal')(),
chalk = require('chalk'),
program duckCount = 0,
.version(version) wabbitCount = 0;
.command('bugfix [options]','Command wrapper for git flow bugfix').alias('b')
.command('config [options]','Command wrapper for git flow config').alias('c') // duck
.command('feature [options]','Command wrapper for git flow feature',{isDefault: true}).alias('fwf') vorpal
.command('hotfix [options]','Command wrapper for git flow hotfix').alias('h') .command('setup', 'Initialize the plugin')
.command('init [options]','Command wrapper for git flow init').alias('i') .action(require('./setup'));
.command('log [options]','Command wrapper for git flow log').alias('l') vorpal
.command('release [options]','Command wrapper for git release').alias('r') .command('init', 'Initialize a new git repo with support for the branching model.')
.command('support [options]','Command wrapper for git support').alias('s') .action(require('./init'));
.parse(process.argv); vorpal
\ No newline at end of file .command('feature', 'Manage your feature branches.')
.action(require('./feature'));
vorpal
.command('release', 'Manage your release branches.')
.action(require('./release'));
vorpal
.command('hotfix', 'Manage your hotfix branches.')
.action(require('./hotfix'));
vorpal
.command('support', 'Manage your support branches')
.action(require('./support'));
vorpal
.command('bugfix', 'Manage your bugfix branches')
.action(require('./bugfix'));
vorpal
.command('version', 'Shows version information')
.action(require('./version'));
// vorpal
// .command('init', '')
// .action(require('./init'));
// vorpal
// .command('init', '')
// .action(require('./init'));
// vorpal
// .command('init', '')
// .action(require('./init'));
// vorpal
// .command('duck season', 'Outputs "rabbit season"')
// .action(function(args, callback) {
// duckCount++;
// this.log('Wabbit season');
// callback();
// });
// // wabbit
// vorpal
// .command('wabbit', 'Outputs "duck"')
// .action(function(args, callback) {
// this.log('Duck');
// callback();
// });
// vorpal
// .command('wabbit season', 'Outputs "duck season"')
// .action(function(args, callback) {
// // no cheating
// if (duckCount < 2) {
// duckCount = 0;
// this.log('You\'re despicable');
// callback();
// }
// else if (wabbitCount === 0) {
// wabbitCount++;
// this.log('Duck season');
// callback();
// }
// // doh!
// else {
// this.log('I say it\'s duck season. And I say fire!');
// vorpal.ui.cancel();
// }
// });
vorpal
.delimiter(chalk.cyan('flow$'))
.show();
// echo "usage: git flow <subcommand>"
// echo
// echo "Available subcommands are:"
// echo " init ."
// echo " feature "
// echo " release "
// echo " hotfix "
// echo " support ."
// echo " version ."
// echo
// echo "Try 'git flow <subcommand> help' for details."
\ No newline at end of file
module.exports = function(args, callback) {
this.log('hotfix');
callback();
};
\ No newline at end of file
const fs = require('fs');
const path = require('path');
const resolve = require('resolve');
var NodeGit = require("nodegit");
module.exports = function(args, callback) {
this.log('init');
process.env.PWD = process.env.PWD || process.cwd();
process.env.CLI_ROOT = process.env.CLI_ROOT || path.resolve(__dirname, '..');
var pathToRepo = process.env.PWD
NodeGit.Repository.openExt(pathToRepo,0,'null').then(function (repository) {
console.log('Is a repo');
console.log(repository);
var signature = repository.defaultSignature();
console.log(signature);
}, function (reasonForFailure) {
console.log(' Is not a repo'+reasonForFailure);
// NodeGit.Repository.init(pathToRepo, 0).then(function (repo) {
// // git commit --allow-empty -m "Initial commit"
// repository.createCommit(updateRef, author, committer, message, Tree, parents).then(function(oid) {
// // Use oid
// });
// });
});
// this.log(process.env.PWD);
// this.log(process.env.CLI_ROOT);
callback();
};
\ No newline at end of file
module.exports = function(args, callback) {
this.log('release');
callback();
};
\ No newline at end of file
{"name":"Lassie","valuation":10,"employees":["s"],"dateFounded":{"$$date":1486903613304},"_id":"LN74nukw0czxEQyh"}
require('babel/register');
require('./test.js');
\ No newline at end of file
var connect = require('camo').connect;
var database;
var uri = 'nedb://'+__dirname;
console.log (uri);
connect(uri).then(function(db) {
var Document = require('camo').Document;
class Company extends Document {
constructor() {
super();
this.name = String;
this.valuation = {
type: Number,
default: 10000000000,
min: 0
};
this.employees = [String];
this.dateFounded = {
type: Date,
default: Date.now
};
}
static collectionName() {
return 'companies';
}
}
var company = Company.create({
name: 'Lassie',
valuation: 10,
employees:["s"]
});
company.save().then(function(l) {
console.log(l._id);
});
});
module.exports = function(args, callback) {
this.log('support');
callback();
};
\ No newline at end of file
module.exports = function(args, callback) {
this.log('version');
callback();
};
\ No newline at end of file
language: node_js
node_js:
- "6"
- "5"
- "4"
- "iojs"
notifications:
email: false
cache:
directories:
- node_modules
- build
script:
- npm i -g nexe
- nexe
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment