Merge branch 'release/0.2'
This commit is contained in:
commit
097459c5c5
21 changed files with 1774 additions and 542 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "shFlags"]
|
||||
path = shFlags
|
||||
url = git://github.com/nvie/shFlags.git
|
30
Makefile
Normal file
30
Makefile
Normal file
|
@ -0,0 +1,30 @@
|
|||
AUTO_DETECTED_GIT_EXEC_PATH := $(shell git --exec-path 2>/dev/null || echo /usr/libexec/git-core)
|
||||
GIT_EXEC_PATH=$(AUTO_DETECTED_GIT_EXEC_PATH)
|
||||
|
||||
# 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-hotfix
|
||||
SCRIPT_FILES+=git-flow-release
|
||||
SCRIPT_FILES+=git-flow-support
|
||||
SCRIPT_FILES+=git-flow-version
|
||||
SCRIPT_FILES+=gitflow-common
|
||||
SCRIPT_FILES+=gitflow-shFlags
|
||||
|
||||
all:
|
||||
@echo "usage: make install"
|
||||
@echo " make uninstall"
|
||||
|
||||
install:
|
||||
@test -f gitflow-shFlags || (echo "Run 'git submodule init && git submodule update' first." ; exit 1 )
|
||||
install -d -m 0755 $(GIT_EXEC_PATH)
|
||||
install -m 0755 $(EXEC_FILES) $(GIT_EXEC_PATH)
|
||||
install -m 0644 $(SCRIPT_FILES) $(GIT_EXEC_PATH)
|
||||
|
||||
uninstall:
|
||||
test -d $(GIT_EXEC_PATH) && \
|
||||
cd $(GIT_EXEC_PATH) && \
|
||||
rm -f $(EXEC_FILES) $(SCRIPT_FILES)
|
137
README.mdown
137
README.mdown
|
@ -1,84 +1,95 @@
|
|||
gitflow
|
||||
=======
|
||||
A collection of Git wrapper scripts to provide high-level repository operations
|
||||
for Vincent Driessen's [branching model](http://nvie.com/archives/323 "original
|
||||
git-flow
|
||||
========
|
||||
A collection of Git extensions to provide high-level repository operations
|
||||
for Vincent Driessen's [branching model](http://nvie.com/git-model "original
|
||||
blog post").
|
||||
|
||||
|
||||
Release 0.1
|
||||
-----------
|
||||
A quick release of version 0.1 has arrived. The main script are functional and
|
||||
should be usable under "normal" use.
|
||||
|
||||
There have barely been any real-world tests, but I encourage you to start using
|
||||
it actively. [Feedback](http://github.com/nvie/gitflow/issues) is also very
|
||||
welcome. See the "Please help out" section below, also.
|
||||
|
||||
**Make sure to validate the modifications to your repo after running any of the
|
||||
`gitflow` commands, before pushing them permanently.**
|
||||
> **IMPORTANT NOTE:**
|
||||
> In release 0.2, the order of the arguments has changed to provide a logical
|
||||
> subcommand hierarchy.
|
||||
|
||||
|
||||
Installing gitflow
|
||||
------------------
|
||||
There isn't a real Unix installer available, but the project is so small that
|
||||
installing it is easy.
|
||||
Installing git-flow
|
||||
-------------------
|
||||
After downloading the sources from Github, also fetch the submodules:
|
||||
|
||||
Either:
|
||||
$ git submodule init
|
||||
$ git submodule update
|
||||
|
||||
- Put the `gitflow` directory anywhere on your Unix `PATH` variable; or
|
||||
- Run:
|
||||
|
||||
$ git clone git://github.com/nvie/gitflow
|
||||
$ cd gitflow
|
||||
$ cp gitflow* /usr/local/bin
|
||||
Then, you can install `git-flow`, using:
|
||||
|
||||
$ sudo make install
|
||||
|
||||
By default, this will look for the directory where Git is already installed,
|
||||
and install the git-flow extension alongside the other Git subcommands. If git
|
||||
is not on the system's `PATH`, it tries `/usr/libexec/git-core`. To explicitly
|
||||
override this setting in case you have installed Git in another location, use:
|
||||
|
||||
$ sudo make GIT_EXEC_PATH=/your/custom/path install
|
||||
|
||||
You rarely need to override this manually, the default 'make install' should do
|
||||
fine.
|
||||
|
||||
Or simply point your `PATH` environment variable to your git-flow checkout
|
||||
directory.
|
||||
|
||||
|
||||
Please help out
|
||||
---------------
|
||||
This project is still under development. What is available today is merely its
|
||||
foundation. However, it is functional in its current form and should be usable
|
||||
under normal use. (Don't try to create multiple release branches next to each
|
||||
other and stuff like that, yet.)
|
||||
|
||||
Feedback and suggestions are very welcome and I encourage you to use the
|
||||
[Issues list](http://github.com/nvie/gitflow/issues) on Github to provide that
|
||||
This project is still under development. Feedback and suggestions are very
|
||||
welcome and I encourage you to use the [Issues
|
||||
list](http://github.com/nvie/gitflow/issues) on Github to provide that
|
||||
feedback.
|
||||
|
||||
Feel free to fork this repo and to commit your additions.
|
||||
|
||||
|
||||
Example uses:
|
||||
-------------
|
||||
Typical usage:
|
||||
--------------
|
||||
|
||||
* To start a new feature branch, use:
|
||||
|
||||
gitflow start feature <name> [<base>]
|
||||
gitflow start feature foo-support
|
||||
|
||||
`base` is `develop` by default.
|
||||
### Initialization
|
||||
|
||||
* To finish this feature and have it merged into `develop`, use:
|
||||
To initialize a new repo with the basic branch structure, use:
|
||||
|
||||
gitflow finish feature <name>
|
||||
gitflow finish feature foo-support
|
||||
git flow init
|
||||
|
||||
* To start a new release branch for 2.0, based on the 1.1 production release, use:
|
||||
|
||||
gitflow start release <release>
|
||||
gitflow start release 2.0
|
||||
|
||||
* To finish the release branch (i.e. to make an actual production release), use:
|
||||
|
||||
gitflow finish release <release>
|
||||
gitflow finish release 2.0
|
||||
|
||||
* To start a new hotfix branch for 2.1, based on the 2.0 production release, use:
|
||||
|
||||
gitflow start hotfix <release> [<base-release>]
|
||||
gitflow start hotfix 2.1 2.0
|
||||
|
||||
* To finish the hotfix branch, use:
|
||||
|
||||
gitflow finish hotfix <release>
|
||||
gitflow finish hotfix 2.1
|
||||
This will then interactively prompt you with some questions on which branches
|
||||
you would like to use as development and production branches, and how you
|
||||
would like your prefixes be named. You may simply press Return on any of
|
||||
those questions to accept the (sane) default suggestions.
|
||||
|
||||
|
||||
### Creating feature/release/hotfix/support branches
|
||||
|
||||
* To list/start/finish feature branches, use:
|
||||
|
||||
git flow feature
|
||||
git flow feature start <name> [<base>]
|
||||
git flow feature finish <name>
|
||||
|
||||
For feature branches, the `<base>` arg must be a commit on `develop`.
|
||||
|
||||
* To list/start/finish release branches, use:
|
||||
|
||||
git flow release
|
||||
git flow release start <release> [<base>]
|
||||
git flow release finish <release>
|
||||
|
||||
For release branches, the `<base>` arg must be a commit on `develop`.
|
||||
|
||||
* To list/start/finish hotfix branches, use:
|
||||
|
||||
git flow hotfix
|
||||
git flow hotfix start <release> [<base>]
|
||||
git flow hotfix finish <release>
|
||||
|
||||
For hotfix branches, the `<base>` arg must be a commit on `master`.
|
||||
|
||||
* To list/start support branches, use:
|
||||
|
||||
git flow support
|
||||
git flow support start <release> <base>
|
||||
|
||||
For support branches, the `<base>` arg must be a commit on `master`.
|
||||
|
||||
|
|
15
TODO.mdown
15
TODO.mdown
|
@ -1,15 +0,0 @@
|
|||
TODO-list
|
||||
=========
|
||||
|
||||
General configuration
|
||||
---------------------
|
||||
- Support configurable naming for fixed branch names 'master' and 'develop'
|
||||
- Support configurable naming conventions (i.e. name prefixes) for supporting
|
||||
branches, instead of fixed 'release-\*' and 'hotfix-\*'
|
||||
|
||||
Release branch support
|
||||
----------------------
|
||||
- Take care of the situation where two release branches live next to each
|
||||
other. In that situation, a "finish release" action should merge back changes
|
||||
into the other release, not into 'develop'. Or at least warn about it. Or not
|
||||
support creating a new release branch if the other isn't finished yet.
|
11
bump-version
11
bump-version
|
@ -8,6 +8,11 @@ if [ $# -ne 1 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
echo "GITFLOW_VERSION=$1" > gitflow-version
|
||||
git add gitflow-version
|
||||
git commit -m "Bumped version number to $1" gitflow-version
|
||||
if ! sed 's/^GITFLOW_VERSION=.*$/GITFLOW_VERSION='$1'/g' git-flow-version > .git-flow-version.new; then
|
||||
echo "Could not replace GITFLOW_VERSION variable." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
mv .git-flow-version.new git-flow-version
|
||||
git add git-flow-version
|
||||
git commit -m "Bumped version number to $1" git-flow-version
|
||||
|
|
88
git-flow
Executable file
88
git-flow
Executable file
|
@ -0,0 +1,88 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# git-flow -- A collection of Git extensions to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model.
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
# Copyright (c) 2010 by Benedikt Böhm
|
||||
#
|
||||
|
||||
# enable debug mode
|
||||
if [ "$DEBUG" = "yes" ]; then
|
||||
set -x
|
||||
fi
|
||||
|
||||
export GITFLOW_DIR=$(dirname "$0")
|
||||
|
||||
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 " release Manage your release branches."
|
||||
echo " hotfix Manage your hotfix branches."
|
||||
echo " support Manage your support branches."
|
||||
echo " version Shows version information."
|
||||
echo
|
||||
echo "Try 'git flow <subcommand> help' for details."
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ $# -lt 1 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# load common functionality
|
||||
. "$GITFLOW_DIR/gitflow-common"
|
||||
|
||||
# use the shFlags project to parse the command line arguments
|
||||
. "$GITFLOW_DIR/gitflow-shFlags"
|
||||
FLAGS_PARENT="git flow"
|
||||
FLAGS "$@" || exit $?
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
|
||||
# sanity checks
|
||||
SUBCOMMAND="$1"; shift
|
||||
|
||||
if [ ! -e "$GITFLOW_DIR/git-flow-$SUBCOMMAND" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# run command
|
||||
. "$GITFLOW_DIR/git-flow-$SUBCOMMAND"
|
||||
FLAGS_PARENT="git flow $SUBCOMMAND"
|
||||
|
||||
# test if the first argument is a flag (i.e. starts with '-')
|
||||
# in that case, we interpret this arg as a flag for the default
|
||||
# command
|
||||
SUBACTION="default"
|
||||
if [ "$1" != "" ] && ! echo "$1" | grep -q "^-"; then
|
||||
SUBACTION="$1"; shift
|
||||
fi
|
||||
if ! type "cmd_$SUBACTION" >/dev/null 2>&1; then
|
||||
warn "Unknown subcommand: '$SUBACTION'"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# run the specified action
|
||||
cmd_$SUBACTION "$@"
|
||||
}
|
||||
|
||||
# helper functions for common reuse
|
||||
max() { if [ "$1" -gt "$2" ]; then echo "$1"; else echo "$2"; fi; }
|
||||
|
||||
# convenience functions for checking whether flags have been set or not
|
||||
flag() { eval FLAG=\$FLAGS_$1; [ $FLAG -eq $FLAGS_TRUE ]; }
|
||||
noflag() { eval FLAG=\$FLAGS_$1; [ $FLAG -ne $FLAGS_TRUE ]; }
|
||||
|
||||
main "$@"
|
378
git-flow-feature
Normal file
378
git-flow-feature
Normal file
|
@ -0,0 +1,378 @@
|
|||
#
|
||||
# git-flow -- A collection of Git extensions to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model.
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
# Copyright (c) 2010 by Benedikt Böhm
|
||||
#
|
||||
|
||||
require_git_repo
|
||||
require_gitflow_initialized
|
||||
gitflow_load_settings
|
||||
PREFIX=$(git config --get gitflow.prefix.feature)
|
||||
|
||||
usage() {
|
||||
echo "usage: git flow feature [list] [-v]"
|
||||
echo " git flow feature start [-Ff] <name> [<base>]"
|
||||
echo " git flow feature finish [-rF] <name|nameprefix>"
|
||||
echo " git flow feature publish <name>"
|
||||
echo " git flow feature track <name>"
|
||||
echo " git flow feature diff [<name|nameprefix>]"
|
||||
echo " git flow feature rebase [-i] [<name|nameprefix>]"
|
||||
}
|
||||
|
||||
cmd_default() {
|
||||
cmd_list "$@"
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
DEFINE_boolean verbose false 'verbose (more) output' v
|
||||
parse_args "$@"
|
||||
|
||||
local feature_branches
|
||||
local current_branch
|
||||
local short_names
|
||||
feature_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")
|
||||
if [ -z "$feature_branches" ]; then
|
||||
warn "No feature branches exist."
|
||||
exit 0
|
||||
fi
|
||||
current_branch=$(git branch | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g')
|
||||
short_names=$(echo "$feature_branches" | sed "s ^$PREFIX g")
|
||||
|
||||
# determine column width first
|
||||
local width=0
|
||||
local branch
|
||||
for branch in $short_names; do
|
||||
local len=${#branch}
|
||||
width=$(max $width $len)
|
||||
done
|
||||
width=$(($width+3))
|
||||
|
||||
local branch
|
||||
for branch in $short_names; do
|
||||
local fullname=$PREFIX$branch
|
||||
local base=$(git merge-base "$fullname" "$DEVELOP_BRANCH")
|
||||
local develop_sha=$(git rev-parse "$DEVELOP_BRANCH")
|
||||
local branch_sha=$(git rev-parse "$fullname")
|
||||
if [ "$fullname" = "$current_branch" ]; then
|
||||
printf "* "
|
||||
else
|
||||
printf " "
|
||||
fi
|
||||
if flag verbose; then
|
||||
printf "%-${width}s" "$branch"
|
||||
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"
|
||||
fi
|
||||
echo
|
||||
done
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
usage
|
||||
exit 0
|
||||
}
|
||||
|
||||
require_name_arg() {
|
||||
if [ "$NAME" = "" ]; then
|
||||
warn "Missing argument <name>"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
expand_nameprefix_arg() {
|
||||
require_name_arg
|
||||
|
||||
local expanded_name
|
||||
local exitcode
|
||||
expanded_name=$(gitflow_resolve_nameprefix "$NAME" "$PREFIX")
|
||||
exitcode=$?
|
||||
case $exitcode in
|
||||
0) NAME=$expanded_name
|
||||
BRANCH=$PREFIX$NAME
|
||||
;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
expand_nameprefix_arg_or_current() {
|
||||
if [ "$NAME" != "" ]; then
|
||||
expand_nameprefix_arg
|
||||
require_branch "$PREFIX$NAME"
|
||||
else
|
||||
local current_branch=$(git_current_branch)
|
||||
if startswith "$current_branch" "$PREFIX"; then
|
||||
BRANCH=$current_branch
|
||||
NAME=${BRANCH#$PREFIX}
|
||||
else
|
||||
warn "The current HEAD is no feature branch."
|
||||
warn "To diff a feature, specify a <name> argument."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
# parse options
|
||||
FLAGS "$@" || exit $?
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
|
||||
# read arguments into global variables
|
||||
NAME=$1
|
||||
BRANCH=$PREFIX$NAME
|
||||
}
|
||||
|
||||
cmd_start() {
|
||||
DEFINE_boolean fetch false 'fetch from origin before performing local operation' F
|
||||
DEFINE_boolean force false 'force creation of feature branch (ignores dirty working tree)' f
|
||||
parse_args "$@"
|
||||
BASE=${2:-$DEVELOP_BRANCH}
|
||||
require_name_arg
|
||||
|
||||
# sanity checks
|
||||
if noflag force; then
|
||||
require_clean_working_tree
|
||||
fi
|
||||
require_branch_absent "$BRANCH"
|
||||
|
||||
# update the local repo with remote changes, if asked
|
||||
if flag fetch; then
|
||||
git fetch -q "$ORIGIN" "$DEVELOP_BRANCH"
|
||||
fi
|
||||
|
||||
require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
|
||||
|
||||
# create branch
|
||||
if ! git checkout -b "$BRANCH" "$BASE"; then
|
||||
die "Could not create feature branch '$BRANCH'"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Summary of actions:"
|
||||
echo "- A new branch '$BRANCH' was created, based on '$BASE'"
|
||||
echo "- You are now on branch '$BRANCH'"
|
||||
echo ""
|
||||
echo "Now, start committing on your feature. When done, use:"
|
||||
echo ""
|
||||
echo " git flow finish feature $NAME"
|
||||
echo
|
||||
}
|
||||
|
||||
cmd_finish() {
|
||||
DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F
|
||||
DEFINE_boolean rebase false 'rebase instead of merge' r
|
||||
parse_args "$@"
|
||||
expand_nameprefix_arg
|
||||
|
||||
# sanity checks
|
||||
require_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
|
||||
# succesfull 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
|
||||
|
||||
# update local repo with remote changes first, if asked
|
||||
if flag fetch; then
|
||||
git fetch -q "$ORIGIN" "$BRANCH"
|
||||
fi
|
||||
|
||||
if has "$ORIGIN/$BRANCH" "$(git_remote_branches)"; then
|
||||
require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH"
|
||||
fi
|
||||
require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
|
||||
|
||||
# if the user wants to rebase, do that first
|
||||
if flag rebase; then
|
||||
if ! git flow feature rebase "$NAME" "$DEVELOP_BRANCH"; 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' '$DEVELOP_BRANCH'"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# merge into BASE
|
||||
git checkout "$DEVELOP_BRANCH"
|
||||
if [ "$(git rev-list -n2 "$DEVELOP_BRANCH..$BRANCH" | wc -l)" -eq 1 ]; then
|
||||
git merge --ff "$BRANCH"
|
||||
else
|
||||
git merge --no-ff "$BRANCH"
|
||||
fi
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
# oops.. we have a merge conflict!
|
||||
# write the given $DEVELOP_BRANCH to a temporary file (we need it later)
|
||||
mkdir -p "$DOT_GIT_DIR/.gitflow"
|
||||
echo "$DEVELOP_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
|
||||
|
||||
# when no merge conflict is detected, just clean up the feature branch
|
||||
helper_finish_cleanup
|
||||
}
|
||||
|
||||
helper_finish_cleanup() {
|
||||
# sanity checks
|
||||
require_branch "$BRANCH"
|
||||
require_clean_working_tree
|
||||
|
||||
# delete branch
|
||||
if flag fetch; then
|
||||
git push "$ORIGIN" ":refs/heads/$BRANCH"
|
||||
fi
|
||||
git branch -d "$BRANCH"
|
||||
|
||||
echo
|
||||
echo "Summary of actions:"
|
||||
echo "- The feature branch '$BRANCH' was merged into '$DEVELOP_BRANCH'"
|
||||
#echo "- Merge conflicts were resolved" # TODO: Add this line when it's supported
|
||||
echo "- Feature branch '$BRANCH' has been removed"
|
||||
echo "- You are now on branch '$DEVELOP_BRANCH'"
|
||||
echo
|
||||
}
|
||||
|
||||
cmd_publish() {
|
||||
parse_args "$@"
|
||||
expand_nameprefix_arg
|
||||
|
||||
# sanity checks
|
||||
require_clean_working_tree
|
||||
require_branch "$BRANCH"
|
||||
git fetch -q "$ORIGIN"
|
||||
require_branch_absent "$ORIGIN/$BRANCH"
|
||||
|
||||
# create remote branch
|
||||
git push "$ORIGIN" "$BRANCH:refs/heads/$BRANCH"
|
||||
git fetch -q "$ORIGIN"
|
||||
|
||||
# configure remote tracking
|
||||
git config "branch.$BRANCH.remote" "$ORIGIN"
|
||||
git config "branch.$BRANCH.merge" "refs/heads/$BRANCH"
|
||||
git checkout "$BRANCH"
|
||||
|
||||
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 '$BRANCH'"
|
||||
echo
|
||||
}
|
||||
|
||||
cmd_track() {
|
||||
parse_args "$@"
|
||||
require_name_arg
|
||||
|
||||
# sanity checks
|
||||
require_clean_working_tree
|
||||
require_branch_absent "$BRANCH"
|
||||
git fetch -q "$ORIGIN"
|
||||
require_branch "$ORIGIN/$BRANCH"
|
||||
|
||||
# create tracking branch
|
||||
git 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_diff() {
|
||||
parse_args "$@"
|
||||
|
||||
if [ "$NAME" != "" ]; then
|
||||
expand_nameprefix_arg
|
||||
BASE=$(git merge-base "$DEVELOP_BRANCH" "$BRANCH")
|
||||
git diff "$BASE..$BRANCH"
|
||||
else
|
||||
if ! git_current_branch | grep -q "^$PREFIX"; then
|
||||
die "Not on a feature branch. Name one explicitly."
|
||||
fi
|
||||
|
||||
BASE=$(git merge-base "$DEVELOP_BRANCH" HEAD)
|
||||
git diff "$BASE"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_rebase() {
|
||||
DEFINE_boolean interactive false 'do an interactive rebase' i
|
||||
parse_args "$@"
|
||||
expand_nameprefix_arg_or_current
|
||||
warn "Will try to rebase '$NAME'..."
|
||||
require_clean_working_tree
|
||||
require_branch "$BRANCH"
|
||||
|
||||
git checkout -q "$BRANCH"
|
||||
local OPTS=
|
||||
if flag interactive; then
|
||||
OPTS="$OPTS -i"
|
||||
fi
|
||||
git rebase $OPTS "$DEVELOP_BRANCH"
|
||||
}
|
247
git-flow-hotfix
Normal file
247
git-flow-hotfix
Normal file
|
@ -0,0 +1,247 @@
|
|||
#
|
||||
# git-flow -- A collection of Git extensions to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model.
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
# Copyright (c) 2010 by Benedikt Böhm
|
||||
#
|
||||
|
||||
require_git_repo
|
||||
require_gitflow_initialized
|
||||
gitflow_load_settings
|
||||
VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
|
||||
PREFIX=$(git config --get gitflow.prefix.hotfix)
|
||||
|
||||
usage() {
|
||||
echo "usage: git flow hotfix [list] [-v]"
|
||||
echo " git flow hotfix start [-F] <version> [<base>]"
|
||||
echo " git flow hotfix finish [-Fsump] <version>"
|
||||
}
|
||||
|
||||
cmd_default() {
|
||||
cmd_list "$@"
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
DEFINE_boolean verbose false 'verbose (more) output' v
|
||||
parse_args "$@"
|
||||
|
||||
local hotfix_branches
|
||||
local current_branch
|
||||
local short_names
|
||||
hotfix_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")
|
||||
if [ -z "$hotfix_branches" ]; then
|
||||
warn "No hotfix branches exist."
|
||||
exit 0
|
||||
fi
|
||||
current_branch=$(git branch | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g')
|
||||
short_names=$(echo "$hotfix_branches" | sed "s ^$PREFIX g")
|
||||
|
||||
# determine column width first
|
||||
local width=0
|
||||
local branch
|
||||
for branch in $short_names; do
|
||||
local len=${#branch}
|
||||
width=$(max $width $len)
|
||||
done
|
||||
width=$(($width+3))
|
||||
|
||||
local branch
|
||||
for branch in $short_names; do
|
||||
local fullname=$PREFIX$branch
|
||||
local base=$(git merge-base "$fullname" "$MASTER_BRANCH")
|
||||
local master_sha=$(git rev-parse "$MASTER_BRANCH")
|
||||
local branch_sha=$(git rev-parse "$fullname")
|
||||
if [ "$fullname" = "$current_branch" ]; then
|
||||
printf "* "
|
||||
else
|
||||
printf " "
|
||||
fi
|
||||
if flag verbose; then
|
||||
printf "%-${width}s" "$branch"
|
||||
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"
|
||||
fi
|
||||
echo
|
||||
done
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
usage
|
||||
exit 0
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
# parse options
|
||||
FLAGS "$@" || exit $?
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
|
||||
# read arguments into global variables
|
||||
VERSION=$1
|
||||
BRANCH=$PREFIX$VERSION
|
||||
}
|
||||
|
||||
require_version_arg() {
|
||||
if [ "$VERSION" = "" ]; then
|
||||
warn "Missing argument <version>"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_base_is_on_master() {
|
||||
if ! git branch --contains "$BASE" 2>/dev/null \
|
||||
| sed 's/[* ] //g' \
|
||||
| grep -q "^$MASTER_BRANCH\$"; then
|
||||
die "fatal: Given base '$BASE' is not a valid commit on '$MASTER_BRANCH'."
|
||||
fi
|
||||
}
|
||||
|
||||
require_no_existing_hotfix_branches() {
|
||||
local hotfix_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")
|
||||
local 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() {
|
||||
DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
|
||||
parse_args "$@"
|
||||
BASE=${2:-$MASTER_BRANCH}
|
||||
require_version_arg
|
||||
require_base_is_on_master
|
||||
require_no_existing_hotfix_branches
|
||||
|
||||
# sanity checks
|
||||
require_clean_working_tree
|
||||
require_branch_absent "$BRANCH"
|
||||
require_tag_absent "$VERSION_PREFIX$VERSION"
|
||||
if flag fetch; then
|
||||
git fetch -q "$ORIGIN" "$MASTER_BRANCH"
|
||||
fi
|
||||
require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
|
||||
|
||||
# create branch
|
||||
git checkout -b "$BRANCH" "$BASE"
|
||||
|
||||
echo
|
||||
echo "Summary of actions:"
|
||||
echo "- A new branch '$BRANCH' was created, based on '$BASE'"
|
||||
echo "- You are now on branch '$BRANCH'"
|
||||
echo
|
||||
echo "Follow-up actions:"
|
||||
echo "- Bump the version number now!"
|
||||
echo "- Start committing your hot fixes"
|
||||
echo "- When done, run:"
|
||||
echo
|
||||
echo " git flow hotfix finish '$VERSION'"
|
||||
echo
|
||||
}
|
||||
|
||||
cmd_finish() {
|
||||
DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
|
||||
DEFINE_boolean sign false "sign the release tag cryptographically" s
|
||||
DEFINE_string signingkey "" "use the given GPG-key for the digital signature (implies -s)" u
|
||||
DEFINE_string message "" "use the given tag message" m
|
||||
DEFINE_boolean push false "push to $ORIGIN after performing finish" p
|
||||
parse_args "$@"
|
||||
require_version_arg
|
||||
|
||||
# handle flags that imply other flags
|
||||
if [ "$FLAGS_signingkey" != "" ]; then
|
||||
FLAGS_sign=$FLAGS_TRUE
|
||||
fi
|
||||
|
||||
# sanity checks
|
||||
require_branch "$BRANCH"
|
||||
require_clean_working_tree
|
||||
if flag fetch; then
|
||||
git fetch -q "$ORIGIN" "$MASTER_BRANCH" || \
|
||||
die "Could not fetch $MASTER_BRANCH from $ORIGIN."
|
||||
git fetch -q "$ORIGIN" "$DEVELOP_BRANCH" || \
|
||||
die "Could not fetch $DEVELOP_BRANCH from $ORIGIN."
|
||||
fi
|
||||
require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
|
||||
require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_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 checkout "$MASTER_BRANCH" || \
|
||||
die "Could not check out $MASTER_BRANCH."
|
||||
git merge --no-ff "$BRANCH" || \
|
||||
die "There were merge conflicts."
|
||||
# TODO: What do we do now?
|
||||
fi
|
||||
|
||||
# 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
|
||||
local tagname=$VERSION_PREFIX$VERSION
|
||||
if ! git_tag_exists "$tagname"; then
|
||||
local opts="-a"
|
||||
flag sign && opts="$opts -s"
|
||||
[ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
|
||||
[ "$FLAGS_message" != "" ] && opts="$opts -m '$FLAGS_message'"
|
||||
git tag $opts "$VERSION_PREFIX$VERSION" || \
|
||||
die "Tagging failed. Please run finish again to retry."
|
||||
fi
|
||||
|
||||
# try to merge into develop
|
||||
# in case a previous attempt to finish this release branch has failed,
|
||||
# but the merge into develop was successful, we skip it now
|
||||
if ! git_is_branch_merged_into "$BRANCH" "$DEVELOP_BRANCH"; then
|
||||
git checkout "$DEVELOP_BRANCH" || \
|
||||
die "Could not check out $DEVELOP_BRANCH."
|
||||
|
||||
# TODO: Actually, accounting for 'git describe' pays, so we should
|
||||
# ideally git merge --no-ff $tagname here, instead!
|
||||
git merge --no-ff "$BRANCH" || \
|
||||
die "There were merge conflicts."
|
||||
# TODO: What do we do now?
|
||||
fi
|
||||
|
||||
# delete branch
|
||||
git branch -d "$BRANCH"
|
||||
|
||||
if flag push; then
|
||||
git push "$ORIGIN" "$DEVELOP_BRANCH" || \
|
||||
die "Could not push to $DEVELOP_BRANCH from $ORIGIN."
|
||||
git push "$ORIGIN" "$MASTER_BRANCH" || \
|
||||
die "Could not push to $MASTER_BRANCH from $ORIGIN."
|
||||
git push --tags "$ORIGIN" || \
|
||||
die "Could not push tags to $ORIGIN."
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Summary of actions:"
|
||||
echo "- Latest objects have been fetched from '$ORIGIN'"
|
||||
echo "- Hotfix branch has been merged into '$MASTER_BRANCH'"
|
||||
echo "- The hotfix was tagged '$VERSION_PREFIX$VERSION'"
|
||||
echo "- Hotfix branch has been back-merged into '$DEVELOP_BRANCH'"
|
||||
echo "- Hotfix branch '$BRANCH' has been deleted"
|
||||
if flag push; then
|
||||
echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'"
|
||||
fi
|
||||
echo
|
||||
}
|
237
git-flow-init
Normal file
237
git-flow-init
Normal file
|
@ -0,0 +1,237 @@
|
|||
#
|
||||
# git-flow -- A collection of Git extensions to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model.
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
# Copyright (c) 2010 by Benedikt Böhm
|
||||
#
|
||||
|
||||
usage() {
|
||||
echo "usage: git flow init [-f]"
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
# parse options
|
||||
FLAGS "$@" || exit $?
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
}
|
||||
|
||||
# Default entry when no SUBACTION is given
|
||||
cmd_default() {
|
||||
DEFINE_boolean force false 'force setting of gitflow branches, even if already configured' f
|
||||
parse_args "$@"
|
||||
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
git 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
|
||||
|
||||
local branch_count
|
||||
local answer
|
||||
|
||||
# add a master branch if no such branch exists yet
|
||||
local master_branch
|
||||
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.
|
||||
local default_suggestion
|
||||
local should_check_existence
|
||||
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=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 'production' 'main' 'master'; do
|
||||
if git_local_branch_exists "$guess"; then
|
||||
default_suggestion="$guess"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Branch name for production releases: [$default_suggestion] \c"
|
||||
read answer
|
||||
master_branch=${answer:-$default_suggestion}
|
||||
|
||||
# check existence in case of an already existing repo
|
||||
if [ "$should_check_existence" = "YES" ]; then
|
||||
git_local_branch_exists "$master_branch" || \
|
||||
die "Local branch '$master_branch' does not exist."
|
||||
fi
|
||||
|
||||
# store the name of the master branch
|
||||
git config gitflow.branch.master "$master_branch"
|
||||
fi
|
||||
|
||||
# add a develop branch if no such branch exists yet
|
||||
local develop_branch
|
||||
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)
|
||||
local default_suggestion
|
||||
local should_check_existence
|
||||
branch_count=$(git_local_branches | grep -v "^${master_branch}\$" | wc -l)
|
||||
if [ "$branch_count" -eq 0 ]; then
|
||||
should_check_existence=NO
|
||||
default_suggestion=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 'develop' 'int' 'integration' 'master'; do
|
||||
if git_local_branch_exists "$guess"; then
|
||||
default_suggestion="$guess"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Branch name for \"next release\" development: [$default_suggestion] \c"
|
||||
read answer
|
||||
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 config 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 symbolic-ref HEAD "refs/heads/$master_branch"
|
||||
git 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
|
||||
git branch "$develop_branch" "$master_branch"
|
||||
created_gitflow_branch=1
|
||||
fi
|
||||
|
||||
# assert the gitflow repo has been correctly initialized
|
||||
gitflow_is_initialized
|
||||
|
||||
# switch to develop branch if its newly created
|
||||
if [ $created_gitflow_branch -eq 1 ]; then
|
||||
git checkout -q "$develop_branch"
|
||||
fi
|
||||
|
||||
# finally, ask the user for naming conventions (branch and tag prefixes)
|
||||
echo
|
||||
echo "How to name your supporting branch prefixes?"
|
||||
|
||||
local prefix
|
||||
|
||||
# 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/)
|
||||
echo "Feature branches? [$default_suggestion] \c"
|
||||
read answer
|
||||
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
|
||||
git config gitflow.prefix.feature "$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/)
|
||||
echo "Release branches? [$default_suggestion] \c"
|
||||
read answer
|
||||
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
|
||||
git config 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/)
|
||||
echo "Hotfix branches? [$default_suggestion] \c"
|
||||
read answer
|
||||
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
|
||||
git config 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/)
|
||||
echo "Support branches? [$default_suggestion] \c"
|
||||
read answer
|
||||
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
|
||||
git config 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 "")
|
||||
echo "Version tag prefix? [$default_suggestion] \c"
|
||||
read answer
|
||||
[ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion}
|
||||
git config gitflow.prefix.versiontag "$prefix"
|
||||
fi
|
||||
|
||||
|
||||
# TODO: what to do with origin?
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
usage
|
||||
exit 0
|
||||
}
|
243
git-flow-release
Normal file
243
git-flow-release
Normal file
|
@ -0,0 +1,243 @@
|
|||
#
|
||||
# git-flow -- A collection of Git extensions to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model.
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
# Copyright (c) 2010 by Benedikt Böhm
|
||||
#
|
||||
|
||||
require_git_repo
|
||||
require_gitflow_initialized
|
||||
gitflow_load_settings
|
||||
VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
|
||||
PREFIX=$(git config --get gitflow.prefix.release)
|
||||
|
||||
usage() {
|
||||
echo "usage: git flow release [list] [-v]"
|
||||
echo " git flow release start [-F] <version>"
|
||||
echo " git flow release finish [-Fsump] <version>"
|
||||
}
|
||||
|
||||
cmd_default() {
|
||||
cmd_list "$@"
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
DEFINE_boolean verbose false 'verbose (more) output' v
|
||||
parse_args "$@"
|
||||
|
||||
local release_branches
|
||||
local current_branch
|
||||
local short_names
|
||||
release_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")
|
||||
if [ -z "$release_branches" ]; then
|
||||
warn "No release branches exist."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
current_branch=$(git branch | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g')
|
||||
short_names=$(echo "$release_branches" | sed "s ^$PREFIX g")
|
||||
|
||||
# determine column width first
|
||||
local width=0
|
||||
local branch
|
||||
for branch in $short_names; do
|
||||
local len=${#branch}
|
||||
width=$(max $width $len)
|
||||
done
|
||||
width=$(($width+3))
|
||||
|
||||
local branch
|
||||
for branch in $short_names; do
|
||||
local fullname=$PREFIX$branch
|
||||
local base=$(git merge-base "$fullname" "$DEVELOP_BRANCH")
|
||||
local develop_sha=$(git rev-parse "$DEVELOP_BRANCH")
|
||||
local branch_sha=$(git rev-parse "$fullname")
|
||||
if [ "$fullname" = "$current_branch" ]; then
|
||||
printf "* "
|
||||
else
|
||||
printf " "
|
||||
fi
|
||||
if flag verbose; then
|
||||
printf "%-${width}s" "$branch"
|
||||
if [ "$branch_sha" = "$develop_sha" ]; then
|
||||
printf "(no commits yet)"
|
||||
else
|
||||
local nicename=$(git rev-parse --short "$base")
|
||||
printf "(based on $nicename)"
|
||||
fi
|
||||
else
|
||||
printf "%s" "$branch"
|
||||
fi
|
||||
echo
|
||||
done
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
usage
|
||||
exit 0
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
# parse options
|
||||
FLAGS "$@" || exit $?
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
|
||||
# read arguments into global variables
|
||||
VERSION=$1
|
||||
BRANCH=$PREFIX$VERSION
|
||||
}
|
||||
|
||||
require_version_arg() {
|
||||
if [ "$VERSION" = "" ]; then
|
||||
warn "Missing argument <version>"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_base_is_on_develop() {
|
||||
if ! git branch --contains "$BASE" 2>/dev/null \
|
||||
| sed 's/[* ] //g' \
|
||||
| grep -q "^$DEVELOP_BRANCH\$"; then
|
||||
die "fatal: Given base '$BASE' is not a valid commit on '$DEVELOP_BRANCH'."
|
||||
fi
|
||||
}
|
||||
|
||||
require_no_existing_release_branches() {
|
||||
local release_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")
|
||||
local 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() {
|
||||
DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
|
||||
parse_args "$@"
|
||||
BASE=${2:-$DEVELOP_BRANCH}
|
||||
require_version_arg
|
||||
require_base_is_on_develop
|
||||
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 -q "$ORIGIN" "$DEVELOP_BRANCH"
|
||||
fi
|
||||
require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
|
||||
|
||||
# create branch
|
||||
git checkout -b "$BRANCH" "$BASE"
|
||||
|
||||
echo
|
||||
echo "Summary of actions:"
|
||||
echo "- A new branch '$BRANCH' was created, based on '$BASE'"
|
||||
echo "- You are now on branch '$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() {
|
||||
DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
|
||||
DEFINE_boolean sign false "sign the release tag cryptographically" s
|
||||
DEFINE_string signingkey "" "use the given GPG-key for the digital signature (implies -s)" u
|
||||
DEFINE_string message "" "use the given tag message" m
|
||||
DEFINE_boolean push false "push to $ORIGIN after performing finish" p
|
||||
|
||||
parse_args "$@"
|
||||
require_version_arg
|
||||
|
||||
# handle flags that imply other flags
|
||||
if [ "$FLAGS_signingkey" != "" ]; then
|
||||
FLAGS_sign=$FLAGS_TRUE
|
||||
fi
|
||||
|
||||
# sanity checks
|
||||
require_branch "$BRANCH"
|
||||
require_clean_working_tree
|
||||
if flag fetch; then
|
||||
git fetch -q "$ORIGIN" "$MASTER_BRANCH" || \
|
||||
die "Could not fetch $MASTER_BRANCH from $ORIGIN."
|
||||
git fetch -q "$ORIGIN" "$DEVELOP_BRANCH" || \
|
||||
die "Could not fetch $DEVELOP_BRANCH from $ORIGIN."
|
||||
fi
|
||||
require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
|
||||
require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_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 checkout "$MASTER_BRANCH" || \
|
||||
die "Could not check out $MASTER_BRANCH."
|
||||
git merge --no-ff "$BRANCH" || \
|
||||
die "There were merge conflicts."
|
||||
# TODO: What do we do now?
|
||||
fi
|
||||
|
||||
# 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
|
||||
local tagname=$VERSION_PREFIX$VERSION
|
||||
if ! git_tag_exists "$tagname"; then
|
||||
local opts="-a"
|
||||
flag sign && opts="$opts -s"
|
||||
[ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'"
|
||||
[ "$FLAGS_message" != "" ] && opts="$opts -m '$FLAGS_message'"
|
||||
git tag $opts "$tagname" || \
|
||||
die "Tagging failed. Please run finish again to retry."
|
||||
fi
|
||||
|
||||
# try to merge into develop
|
||||
# in case a previous attempt to finish this release branch has failed,
|
||||
# but the merge into develop was successful, we skip it now
|
||||
if ! git_is_branch_merged_into "$BRANCH" "$DEVELOP_BRANCH"; then
|
||||
git checkout "$DEVELOP_BRANCH" || \
|
||||
die "Could not check out $DEVELOP_BRANCH."
|
||||
|
||||
# TODO: Actually, accounting for 'git describe' pays, so we should
|
||||
# ideally git merge --no-ff $tagname here, instead!
|
||||
git merge --no-ff "$BRANCH" || \
|
||||
die "There were merge conflicts."
|
||||
# TODO: What do we do now?
|
||||
fi
|
||||
|
||||
# delete branch
|
||||
git branch -d "$BRANCH"
|
||||
|
||||
if flag push; then
|
||||
git push "$ORIGIN" "$DEVELOP_BRANCH" || \
|
||||
die "Could not push to $DEVELOP_BRANCH from $ORIGIN."
|
||||
git push "$ORIGIN" "$MASTER_BRANCH" || \
|
||||
die "Could not push to $MASTER_BRANCH from $ORIGIN."
|
||||
git push --tags "$ORIGIN" || \
|
||||
die "Could not push tags to $ORIGIN."
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Summary of actions:"
|
||||
echo "- Latest objects have been fetched from '$ORIGIN'"
|
||||
echo "- Release branch has been merged into '$MASTER_BRANCH'"
|
||||
echo "- The release was tagged '$tagname'"
|
||||
echo "- Release branch has been back-merged into '$DEVELOP_BRANCH'"
|
||||
echo "- Release branch '$BRANCH' has been deleted"
|
||||
if flag push; then
|
||||
echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'"
|
||||
fi
|
||||
echo
|
||||
}
|
153
git-flow-support
Normal file
153
git-flow-support
Normal file
|
@ -0,0 +1,153 @@
|
|||
#
|
||||
# git-flow -- A collection of Git extensions to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model.
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
# Copyright (c) 2010 by Benedikt Böhm
|
||||
#
|
||||
|
||||
require_git_repo
|
||||
require_gitflow_initialized
|
||||
gitflow_load_settings
|
||||
VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
|
||||
PREFIX=$(git config --get gitflow.prefix.support)
|
||||
|
||||
warn "note: The support subcommand is still very EXPERIMENTAL!"
|
||||
warn "note: DO NOT use it in a production situation."
|
||||
|
||||
usage() {
|
||||
echo "usage: git flow support [list] [-v]"
|
||||
echo " git flow support start [-F] <version> <base>"
|
||||
}
|
||||
|
||||
cmd_default() {
|
||||
cmd_list "$@"
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
DEFINE_boolean verbose false 'verbose (more) output' v
|
||||
parse_args "$@"
|
||||
|
||||
local support_branches
|
||||
local current_branch
|
||||
local short_names
|
||||
support_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX")
|
||||
if [ -z "$support_branches" ]; then
|
||||
warn "No support branches exist."
|
||||
exit 0
|
||||
fi
|
||||
current_branch=$(git branch | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g')
|
||||
short_names=$(echo "$support_branches" | sed "s ^$PREFIX g")
|
||||
|
||||
# determine column width first
|
||||
local width=0
|
||||
local branch
|
||||
for branch in $short_names; do
|
||||
local len=${#branch}
|
||||
width=$(max $width $len)
|
||||
done
|
||||
width=$(($width+3))
|
||||
|
||||
local branch
|
||||
for branch in $short_names; do
|
||||
local fullname=$PREFIX$branch
|
||||
local base=$(git merge-base "$fullname" "$MASTER_BRANCH")
|
||||
local master_sha=$(git rev-parse "$MASTER_BRANCH")
|
||||
local branch_sha=$(git rev-parse "$fullname")
|
||||
if [ "$fullname" = "$current_branch" ]; then
|
||||
printf "* "
|
||||
else
|
||||
printf " "
|
||||
fi
|
||||
if flag verbose; then
|
||||
printf "%-${width}s" "$branch"
|
||||
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"
|
||||
fi
|
||||
echo
|
||||
done
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
usage
|
||||
exit 0
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
# parse options
|
||||
FLAGS "$@" || exit $?
|
||||
eval set -- "${FLAGS_ARGV}"
|
||||
|
||||
# read arguments into global variables
|
||||
VERSION=$1
|
||||
BASE=$2
|
||||
BRANCH=$PREFIX$VERSION
|
||||
}
|
||||
|
||||
require_version_arg() {
|
||||
if [ "$VERSION" = "" ]; then
|
||||
warn "Missing argument <version>"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_base_arg() {
|
||||
if [ "$BASE" = "" ]; then
|
||||
warn "Missing argument <base>"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_base_is_on_master() {
|
||||
if ! git branch --contains "$BASE" 2>/dev/null \
|
||||
| sed 's/[* ] //g' \
|
||||
| grep -q "^$MASTER_BRANCH\$"; then
|
||||
die "fatal: Given base '$BASE' is not a valid commit on '$MASTER_BRANCH'."
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_start() {
|
||||
DEFINE_boolean fetch true "fetch from $ORIGIN before performing finish" F
|
||||
parse_args "$@"
|
||||
require_version_arg
|
||||
require_base_arg
|
||||
require_base_is_on_master
|
||||
|
||||
# sanity checks
|
||||
require_clean_working_tree
|
||||
|
||||
# fetch remote changes
|
||||
if flag fetch; then
|
||||
git fetch -q "$ORIGIN" "$BASE"
|
||||
fi
|
||||
require_branch_absent "$BRANCH"
|
||||
|
||||
# create branch
|
||||
git checkout -b "$BRANCH" "$BASE"
|
||||
|
||||
echo
|
||||
echo "Summary of actions:"
|
||||
echo "- A new branch '$BRANCH' was created, based on '$BASE'"
|
||||
echo "- You are now on branch '$BRANCH'"
|
||||
echo
|
||||
}
|
27
git-flow-version
Normal file
27
git-flow-version
Normal file
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
# git-flow -- A collection of Git extensions to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model.
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
# Copyright (c) 2010 by Benedikt Böhm
|
||||
#
|
||||
GITFLOW_VERSION=0.2
|
||||
|
||||
usage() {
|
||||
echo "usage: git flow version"
|
||||
}
|
||||
|
||||
cmd_default() {
|
||||
echo "$GITFLOW_VERSION"
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
usage
|
||||
exit 0
|
||||
}
|
62
gitflow
62
gitflow
|
@ -1,62 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# gitflow -- A collection of Git wrapper scripts to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model:
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
#
|
||||
|
||||
export GITFLOW_DIR=$(dirname "$0")
|
||||
|
||||
usage() {
|
||||
. "$GITFLOW_DIR/gitflow-version"
|
||||
echo "gitflow, version $GITFLOW_VERSION"
|
||||
echo ""
|
||||
echo "usage: gitflow <start|finish> <type> <args>"
|
||||
echo ""
|
||||
echo "arguments:"
|
||||
echo "type can be any of: \"feature\", \"release\", \"hotfix\""
|
||||
echo ""
|
||||
}
|
||||
|
||||
check_incoming() {
|
||||
if [ "$ACTION" != "start" -a "$ACTION" != "finish" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$BTYPE" != "feature" -a "$BTYPE" != "release" -a "$BTYPE" != "hotfix" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
if [ $# -lt 2 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set & check arguments
|
||||
ACTION="$1"
|
||||
BTYPE="$2"
|
||||
shift 2
|
||||
check_incoming
|
||||
|
||||
# Now, $ACTION and $BTYPE are set
|
||||
# It's time to call the appropriate subcommand
|
||||
. "$GITFLOW_DIR/gitflow-sh-setup"
|
||||
. "$GITFLOW_DIR/gitflow-$BTYPE"
|
||||
|
||||
if [ "$ACTION" = "start" ]; then
|
||||
start "$@"
|
||||
elif [ "$ACTION" = "finish" ]; then
|
||||
finish "$@"
|
||||
else
|
||||
usage
|
||||
fi
|
284
gitflow-common
Normal file
284
gitflow-common
Normal file
|
@ -0,0 +1,284 @@
|
|||
#
|
||||
# git-flow -- A collection of Git extensions to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model.
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
# Copyright (c) 2010 by Benedikt Böhm
|
||||
#
|
||||
|
||||
#
|
||||
# Common functionality
|
||||
#
|
||||
|
||||
# shell output
|
||||
warn() { echo "$@" >&2; }
|
||||
die() { warn "$@"; exit 1; }
|
||||
|
||||
# set logic
|
||||
has() {
|
||||
local item=$1; shift
|
||||
echo " $@ " | grep -q " $item "
|
||||
}
|
||||
|
||||
# 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 ]; }
|
||||
|
||||
#
|
||||
# Git specific common functionality
|
||||
#
|
||||
|
||||
git_local_branches() { git branch | sed 's/^[* ] //'; }
|
||||
git_remote_branches() { git branch -r | sed 's/^[* ] //'; }
|
||||
git_all_branches() { ( git branch; git branch -r) | sed 's/^[* ] //'; }
|
||||
git_all_tags() { git tag; }
|
||||
|
||||
git_current_branch() {
|
||||
git branch | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g'
|
||||
}
|
||||
|
||||
git_is_clean_working_tree() {
|
||||
if ! git diff --no-ext-diff --ignore-submodules --quiet --exit-code; then
|
||||
return 1
|
||||
elif ! git diff-index --cached --quiet --ignore-submodules HEAD --; then
|
||||
return 2
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
git_repo_is_headless() {
|
||||
! git rev-parse --quiet --verify HEAD >/dev/null 2>&1
|
||||
}
|
||||
|
||||
git_local_branch_exists() {
|
||||
has $1 $(git_local_branches)
|
||||
}
|
||||
|
||||
git_branch_exists() {
|
||||
has $1 $(git_all_branches)
|
||||
}
|
||||
|
||||
git_tag_exists() {
|
||||
has $1 $(git_all_tags)
|
||||
}
|
||||
|
||||
#
|
||||
# git_compare_branches()
|
||||
#
|
||||
# Tests whether branches and their "origin" counterparts have diverged and need
|
||||
# merging first. It returns error codes to provide more detail, like so:
|
||||
#
|
||||
# 0 Branch heads point to the same commit
|
||||
# 1 First given branch needs fast-forwarding
|
||||
# 2 Second given branch needs fast-forwarding
|
||||
# 3 Branch needs a real merge
|
||||
# 4 There is no merge base, i.e. the branches have no common ancestors
|
||||
#
|
||||
git_compare_branches() {
|
||||
local commit1=$(git rev-parse "$1")
|
||||
local commit2=$(git rev-parse "$2")
|
||||
if [ "$commit1" != "$commit2" ]; then
|
||||
local 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 succesfully merged into $2
|
||||
#
|
||||
git_is_branch_merged_into() {
|
||||
local subject=$1
|
||||
local base=$2
|
||||
local all_merges=$(git branch --contains $subject | sed 's/^[* ] //')
|
||||
has $base $all_merges
|
||||
}
|
||||
|
||||
#
|
||||
# gitflow specific common functionality
|
||||
#
|
||||
|
||||
# check if this repo has been inited for gitflow
|
||||
gitflow_has_master_configured() {
|
||||
local master=$(git config --get gitflow.branch.master)
|
||||
[ "$master" != "" ] && git_local_branch_exists "$master"
|
||||
}
|
||||
|
||||
gitflow_has_develop_configured() {
|
||||
local develop=$(git config --get gitflow.branch.develop)
|
||||
[ "$develop" != "" ] && git_local_branch_exists "$develop"
|
||||
}
|
||||
|
||||
gitflow_has_prefixes_configured() {
|
||||
git config --get gitflow.prefix.feature >/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
|
||||
}
|
||||
|
||||
gitflow_is_initialized() {
|
||||
gitflow_has_master_configured && \
|
||||
gitflow_has_develop_configured && \
|
||||
[ "$(git config --get gitflow.branch.master)" != \
|
||||
"$(git config --get gitflow.branch.develop)" ] && \
|
||||
gitflow_has_prefixes_configured
|
||||
}
|
||||
|
||||
# loading settings that can be overridden using git config
|
||||
gitflow_load_settings() {
|
||||
export DOT_GIT_DIR=$(git rev-parse --git-dir >/dev/null 2>&1)
|
||||
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_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=$1
|
||||
local prefix=$2
|
||||
local matches
|
||||
local num_matches
|
||||
|
||||
# first, check if there is a perfect match
|
||||
if has "$(git_local_branches)" "$prefix$name"; then
|
||||
echo "$name"
|
||||
return 0
|
||||
fi
|
||||
|
||||
matches=$(echo "$(git_local_branches)" | grep "^$prefix$name")
|
||||
num_matches=$(echo "$matches" | wc -l)
|
||||
if [ -z "$matches" ]; then
|
||||
# no prefix match, so take it literally
|
||||
warn "No branch matches 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
|
||||
}
|
||||
|
||||
#
|
||||
# Assertions for use in git-flow subcommands
|
||||
#
|
||||
|
||||
require_git_repo() {
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
die "fatal: Not a git repository"
|
||||
fi
|
||||
}
|
||||
|
||||
require_gitflow_initialized() {
|
||||
if ! gitflow_is_initialized; then
|
||||
die "fatal: Not a gitflow-enabled repo yet. Please run \"git flow init\" first."
|
||||
fi
|
||||
}
|
||||
|
||||
require_clean_working_tree() {
|
||||
git_is_clean_working_tree
|
||||
local result=$?
|
||||
if [ $result -eq 1 ]; then
|
||||
die "fatal: Working tree contains unstaged changes. Aborting."
|
||||
fi
|
||||
if [ $result -eq 2 ]; then
|
||||
die "fatal: Index contains uncommited changes. Aborting."
|
||||
fi
|
||||
}
|
||||
|
||||
require_local_branch() {
|
||||
if ! git_local_branch_exists $1; then
|
||||
die "fatal: Local branch '$1' does not exist and is required."
|
||||
fi
|
||||
}
|
||||
|
||||
require_remote_branch() {
|
||||
if ! has $1 $(git_remote_branches); then
|
||||
die "Remote branch '$1' does not exist and is required."
|
||||
fi
|
||||
}
|
||||
|
||||
require_branch() {
|
||||
if ! has $1 $(git_all_branches); then
|
||||
die "Branch '$1' does not exist and is required."
|
||||
fi
|
||||
}
|
||||
|
||||
require_branch_absent() {
|
||||
if has $1 $(git_all_branches); then
|
||||
die "Branch '$1' already exists. Pick another name."
|
||||
fi
|
||||
}
|
||||
|
||||
require_tag_absent() {
|
||||
if has $1 $(git_all_tags); then
|
||||
die "Tag '$1' already exists. Pick another name."
|
||||
fi
|
||||
}
|
||||
|
||||
require_branches_equal() {
|
||||
require_local_branch "$1"
|
||||
require_remote_branch "$2"
|
||||
git_compare_branches "$1" "$2"
|
||||
local status=$?
|
||||
if [ $status -gt 0 ]; then
|
||||
warn "Branches '$1' and '$2' have diverged."
|
||||
if [ $status -eq 1 ]; then
|
||||
die "And branch '$1' may be fast-forwarded."
|
||||
elif [ $status -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
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# gitflow -- A collection of Git wrapper scripts to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model:
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
#
|
||||
|
||||
usage() {
|
||||
echo "usage: gitflow start feature [<options>] <name> [<base>]"
|
||||
echo " gitflow finish feature [<options>] <name>"
|
||||
# TODO
|
||||
#echo ""
|
||||
#echo "options:"
|
||||
#echo "--option Explanation"
|
||||
#echo ""
|
||||
#echo "start-only options:"
|
||||
#echo "--option Explanation"
|
||||
#echo ""
|
||||
#echo "finish-only options:"
|
||||
#echo "--rebase Rebases the feature branch on top of develop, instead of merging"
|
||||
#echo "--squash Squashes all commits of the feature branch into a single commit"
|
||||
#echo " on develop"
|
||||
#echo "--push Push to the origin repo when finished"
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
FEATURE="$1"
|
||||
if [ $# -eq 2 ]; then
|
||||
BASE="$2"
|
||||
else
|
||||
BASE="develop"
|
||||
fi
|
||||
if [ "$FEATURE" = "" ]; then
|
||||
echo "Missing argument <release>"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
start() {
|
||||
parse_args "$@"
|
||||
|
||||
# Checks
|
||||
gitflow_check_clean_working_tree
|
||||
gitflow_require_branch_absent "$FEATURE"
|
||||
if [ "$BASE" = "develop" ]; then
|
||||
gitflow_require_branches_equal 'develop' 'origin/develop'
|
||||
fi
|
||||
|
||||
# All checks passed, ready to roll
|
||||
git checkout -b "$FEATURE" "$BASE"
|
||||
|
||||
echo ""
|
||||
echo "Summary of actions:"
|
||||
echo "- A new branch '$FEATURE' was created, based on '$BASE'"
|
||||
echo "- You are now on branch '$FEATURE'"
|
||||
echo ""
|
||||
echo "Now, start committing on your feature. When done, use:"
|
||||
echo ""
|
||||
echo " gitflow finish feature '$FEATURE'"
|
||||
}
|
||||
|
||||
finish() {
|
||||
parse_args "$@"
|
||||
|
||||
# Checks
|
||||
gitflow_check_clean_working_tree
|
||||
gitflow_require_branch "$FEATURE"
|
||||
gitflow_require_branches_equal 'develop' 'origin/develop'
|
||||
|
||||
# All checks passed, ready to roll
|
||||
git checkout develop
|
||||
|
||||
# In case there has been only a single commit in the feature branch, don't
|
||||
# use --no-ff, since it has no extra advantages
|
||||
FF_FLAG="--no-ff"
|
||||
if [ "$(git rev-list develop.."$FEATURE" | wc -l)" -eq 1 ]; then
|
||||
FF_FLAG="--ff"
|
||||
fi
|
||||
git merge "$FF_FLAG" "$FEATURE"
|
||||
# TODO: How do we handle merge conflicts here??
|
||||
git branch -d "$FEATURE"
|
||||
|
||||
echo ""
|
||||
echo "Summary of actions:"
|
||||
echo "- The feature branch '$FEATURE' was merged into 'develop'"
|
||||
#echo "- Merge conflicts were resolved" # TODO: Add this line when it's supported
|
||||
echo "- Feature branch '$FEATURE' has been removed"
|
||||
echo "- You are now on branch 'develop'"
|
||||
echo ""
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# gitflow -- A collection of Git wrapper scripts to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model:
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
#
|
||||
|
||||
usage() {
|
||||
echo "usage: gitflow start hotfix <release>"
|
||||
echo " gitflow finish hotfix <release>"
|
||||
# TODO
|
||||
#echo ""
|
||||
#echo "options:"
|
||||
#echo "--option Explanation"
|
||||
#echo ""
|
||||
#echo "start-only options:"
|
||||
#echo "--option Explanation"
|
||||
#echo ""
|
||||
#echo "finish-only options:"
|
||||
#echo "--push Push to the origin repo when finished"
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
RELEASE="$1"
|
||||
if [ "$RELEASE" = "" ]; then
|
||||
echo "Missing argument <release>"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
HOTFIX_BRANCH="hotfix-$RELEASE"
|
||||
}
|
||||
|
||||
start() {
|
||||
parse_args "$@"
|
||||
|
||||
# Checks
|
||||
gitflow_check_clean_working_tree
|
||||
gitflow_require_branches_equal 'master' 'origin/master'
|
||||
gitflow_require_branch_absent "$HOTFIX_BRANCH"
|
||||
|
||||
# All checks passed, ready to roll
|
||||
git checkout -b "$HOTFIX_BRANCH" master
|
||||
|
||||
echo ""
|
||||
echo "Summary of actions:"
|
||||
echo "- A new branch '$HOTFIX_BRANCH' was created, based on 'master'"
|
||||
echo "- You are now on branch '$HOTFIX_BRANCH'"
|
||||
echo ""
|
||||
echo "Follow-up actions:"
|
||||
echo "- Bump the version number now!"
|
||||
echo "- Start committing your hot fixes"
|
||||
echo "- When done, run:"
|
||||
echo ""
|
||||
echo " gitflow finish hotfix '$HOTFIX_BRANCH'"
|
||||
}
|
||||
|
||||
finish() {
|
||||
parse_args "$@"
|
||||
|
||||
# Checks
|
||||
gitflow_check_clean_working_tree
|
||||
|
||||
git fetch origin develop # TODO: Make a flag to skip these fetches
|
||||
git fetch origin master # TODO: Make a flag to skip these fetches
|
||||
gitflow_require_branches_equal 'master' 'origin/master'
|
||||
gitflow_require_branches_equal 'develop' 'origin/develop'
|
||||
|
||||
# All checks passed, ready to roll
|
||||
git checkout master
|
||||
git merge --no-ff "$HOTFIX_BRANCH"
|
||||
git tag "$RELEASE"
|
||||
git checkout develop
|
||||
git merge --no-ff "$HOTFIX_BRANCH"
|
||||
git branch -d "$HOTFIX_BRANCH"
|
||||
|
||||
# TODO: Implement an optional push to master
|
||||
# git push origin develop; git push origin master; git push --tags origin
|
||||
|
||||
echo ""
|
||||
echo "Summary of actions:"
|
||||
echo "- Latest objects have been fetched from 'origin'"
|
||||
echo "- Hotfix branch has been merged into 'master'"
|
||||
echo "- The hotfix was tagged '$RELEASE'"
|
||||
echo "- Hotfix branch has been back-merged into 'develop'"
|
||||
echo "- Hotfix branch '$HOTFIX_BRANCH' has been deleted"
|
||||
echo ""
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# gitflow -- A collection of Git wrapper scripts to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model:
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
#
|
||||
|
||||
usage() {
|
||||
echo "usage: gitflow start release <release>"
|
||||
echo " gitflow finish release <release>"
|
||||
# TODO
|
||||
#echo ""
|
||||
#echo "options:"
|
||||
#echo "--option Explanation"
|
||||
#echo ""
|
||||
#echo "start-only options:"
|
||||
#echo "--bump <script>"
|
||||
#echo " Run the given script to auto-update the version number"
|
||||
#echo ""
|
||||
#echo "finish-only options:"
|
||||
#echo "--push Push to the origin repo when finished"
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
RELEASE="$1"
|
||||
if [ "$RELEASE" = "" ]; then
|
||||
echo "Missing argument <release>"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
RELEASE_BRANCH="release-$RELEASE"
|
||||
}
|
||||
|
||||
start() {
|
||||
parse_args "$@"
|
||||
|
||||
# Checks
|
||||
gitflow_check_clean_working_tree
|
||||
gitflow_require_branches_equal 'develop' 'origin/develop'
|
||||
gitflow_require_branch_absent "$RELEASE_BRANCH"
|
||||
|
||||
# All checks passed, ready to roll
|
||||
git checkout -b "$RELEASE_BRANCH" develop
|
||||
|
||||
echo ""
|
||||
echo "Summary of actions:"
|
||||
echo "- A new branch '$RELEASE_BRANCH' was created, based on 'develop'"
|
||||
echo "- You are now on branch '$RELEASE_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 " gitflow finish release '$RELEASE_BRANCH'"
|
||||
}
|
||||
|
||||
finish() {
|
||||
parse_args "$@"
|
||||
|
||||
# Checks
|
||||
gitflow_check_clean_working_tree
|
||||
|
||||
git fetch origin develop # TODO: Make a flag to skip these fetches
|
||||
git fetch origin master # TODO: Make a flag to skip these fetches
|
||||
gitflow_require_branches_equal 'master' 'origin/master'
|
||||
gitflow_require_branches_equal 'develop' 'origin/develop'
|
||||
|
||||
# All checks passed, ready to roll
|
||||
git checkout master
|
||||
git merge --no-ff "$RELEASE_BRANCH"
|
||||
git tag "$RELEASE"
|
||||
git checkout develop
|
||||
git merge --no-ff "$RELEASE_BRANCH"
|
||||
git branch -d "$RELEASE_BRANCH"
|
||||
|
||||
# TODO: Implement an optional push to master
|
||||
# git push origin develop; git push origin master; git push --tags origin
|
||||
|
||||
echo ""
|
||||
echo "Summary of actions:"
|
||||
echo "- Latest objects have been fetched from 'origin'"
|
||||
echo "- Release branch has been merged into 'master'"
|
||||
echo "- The release was tagged '$RELEASE'"
|
||||
echo "- Release branch has been back-merged into 'develop'"
|
||||
echo "- Release branch '$RELEASE_BRANCH' has been deleted"
|
||||
echo ""
|
||||
}
|
||||
|
108
gitflow-sh-setup
108
gitflow-sh-setup
|
@ -1,108 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# gitflow -- A collection of Git wrapper scripts to provide high-level
|
||||
# repository operations for Vincent Driessen's branching model:
|
||||
#
|
||||
# Original blog post presenting this model is found at:
|
||||
# http://nvie.com/archives/323
|
||||
#
|
||||
# Feel free to contribute to this project at:
|
||||
# http://github.com/nvie/gitflow
|
||||
#
|
||||
# Copyright (c) 2010 by Vincent Driessen
|
||||
#
|
||||
|
||||
# Get the git dir
|
||||
GIT_DIR=$(git rev-parse --git-dir)
|
||||
|
||||
# Get all available branches
|
||||
LOCAL_BRANCHES=$(git branch | sed 's/^[* ] //')
|
||||
REMOTE_BRANCHES=$(git branch -r | sed 's/^[* ] //')
|
||||
ALL_BRANCHES="$LOCAL_BRANCHES\n$REMOTE_BRANCHES"
|
||||
|
||||
warn() { echo "$@" >&2; }
|
||||
die() { warn "$@"; exit 1; }
|
||||
|
||||
gitflow_check_clean_working_tree() {
|
||||
if [ "$(git status 2>/dev/null | tail -n1)" != "nothing to commit (working directory clean)" ]; then
|
||||
die "Working directory is dirty. Only use gitflow in clean working directories for your own safety."
|
||||
fi
|
||||
}
|
||||
|
||||
gitflow_require_local_branch() {
|
||||
echo "$LOCAL_BRANCHES" | grep "^$1\$" 2>&1 >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
die "Local branch '$1' does not exist and is required."
|
||||
fi
|
||||
}
|
||||
|
||||
gitflow_require_remote_branch() {
|
||||
echo "$REMOTE_BRANCHES" | grep "^$1\$" 2>&1 >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
die "Remote branch '$1' does not exist and is required."
|
||||
fi
|
||||
}
|
||||
|
||||
gitflow_require_branch() {
|
||||
echo "$ALL_BRANCHES" | grep "^$1\$" 2>&1 >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
die "Branch '$1' does not exist and is required."
|
||||
fi
|
||||
}
|
||||
|
||||
gitflow_require_branch_absent() {
|
||||
echo "$ALL_BRANCHES" | grep "^$1\$" 2>&1 >/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
die "Branch '$1' already exists. Pick another name."
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# gitflow_test_branches_equal()
|
||||
#
|
||||
# Tests whether branches and their "origin" counterparts have diverged and need
|
||||
# merging first. It returns error codes to provide more detail, like so:
|
||||
#
|
||||
# 0 Branch heads point to the same commit
|
||||
# 1 First given branch needs fast-forwarding
|
||||
# 2 Second given branch needs fast-forwarding
|
||||
# 3 Branch needs a real merge
|
||||
#
|
||||
gitflow_test_branches_equal() {
|
||||
commit1=$(git rev-parse "$1")
|
||||
commit2=$(git rev-parse "$2")
|
||||
if [ "$commit1" != "$commit2" ]; then
|
||||
base=$(git merge-base "$commit1" "$commit2")
|
||||
short_base=$(git rev-parse --short "$base")
|
||||
|
||||
if [ "$commit1" = "$base" ]; then
|
||||
return 1
|
||||
elif [ "$commit2" = "$base" ]; then
|
||||
return 2
|
||||
else
|
||||
return 3
|
||||
fi
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
gitflow_require_branches_equal() {
|
||||
gitflow_require_local_branch "$1"
|
||||
gitflow_require_remote_branch "$2"
|
||||
gitflow_test_branches_equal "$1" "$2"
|
||||
status=$?
|
||||
if [ $status -gt 0 ]; then
|
||||
warn "Branches '$1' and '$2' have diverged."
|
||||
|
||||
if [ $status -eq 1 ]; then
|
||||
die "And branch '$1' may be fast-forwarded."
|
||||
elif [ $status -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
|
||||
}
|
||||
|
1
gitflow-shFlags
Symbolic link
1
gitflow-shFlags
Symbolic link
|
@ -0,0 +1 @@
|
|||
shFlags/src/shflags
|
|
@ -1 +0,0 @@
|
|||
GITFLOW_VERSION=0.1
|
1
shFlags
Submodule
1
shFlags
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 2fb06af13de884e9680f14a00c82e52a67c867f1
|
Loading…
Reference in a new issue