Merge branch 'feature/init-errors' into develop
diff --git a/git-flow b/git-flow
index 7f8c90c..84adc05 100755
--- a/git-flow
+++ b/git-flow
@@ -19,11 +19,6 @@
fi
export GITFLOW_DIR=$(dirname "$0")
-export GIT_DIR=$(git rev-parse --git-dir)
-export MASTER_BRANCH=$(git config --get gitflow.branch.master || echo master)
-export DEVELOP_BRANCH=$(git config --get gitflow.branch.develop || echo develop)
-export ORIGIN=$(git config --get gitflow.origin || echo origin)
-export README=$(git config --get gitflow.readme || echo README)
usage() {
echo "usage: git flow <subcommand>"
@@ -62,10 +57,6 @@
exit 1
fi
- if ! git rev-parse --git-dir >/dev/null; then
- die "Not a git repository"
- fi
-
# run command
. "$GITFLOW_DIR/git-flow-$SUBCOMMAND"
FLAGS_PARENT="git flow $SUBCOMMAND"
diff --git a/git-flow-feature b/git-flow-feature
index d65da94..d005648 100644
--- a/git-flow-feature
+++ b/git-flow-feature
@@ -12,7 +12,10 @@
# Copyright (c) 2010 by Benedikt Böhm
#
-PREFIX=$(git config --get gitflow.prefix.feature || echo feature/)
+gitflow_require_git_repo
+gitflow_require_initialized
+gitflow_load_settings
+PREFIX=$(git config --get gitflow.prefix.feature)
usage() {
echo "usage: git flow feature [list] [-v]"
@@ -35,7 +38,7 @@
local feature_branches
local current_branch
local short_names
- feature_branches=$(echo "$LOCAL_BRANCHES" | grep "^$PREFIX")
+ feature_branches=$(echo "$(gitflow_local_branches)" | grep "^$PREFIX")
if [ -z "$feature_branches" ]; then
warn "No feature branches exist."
exit 0
@@ -184,7 +187,7 @@
gitflow_require_branch "$BRANCH"
# detect if we're restoring from a merge conflict
- if [ -f "$GIT_DIR/.gitflow/MERGE_BASE" ]; then
+ 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
@@ -195,20 +198,20 @@
# exit code for "unmerged changes in working tree", which we should
# actually be testing for here
if gitflow_test_clean_working_tree; then
- FINISH_BASE=$(cat "$GIT_DIR/.gitflow/MERGE_BASE")
+ 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 gitflow_is_branch_merged_into()
if gitflow_is_branch_merged_into "$BRANCH" "$FINISH_BASE"; then
- rm -f "$GIT_DIR/.gitflow/MERGE_BASE"
+ 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 "$GIT_DIR/.gitflow/MERGE_BASE"
+ rm -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE"
fi
else
echo
@@ -231,7 +234,7 @@
git fetch -q "$ORIGIN" "$BRANCH"
fi
- if has "$ORIGIN/$BRANCH" "$REMOTE_BRANCHES"; then
+ if has "$ORIGIN/$BRANCH" "$(gitflow_remote_branches)"; then
gitflow_require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH"
fi
gitflow_require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
@@ -258,8 +261,8 @@
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 "$GIT_DIR/.gitflow"
- echo "$DEVELOP_BRANCH" > "$GIT_DIR/.gitflow/MERGE_BASE"
+ 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"
diff --git a/git-flow-hotfix b/git-flow-hotfix
index 9def3af..347b811 100644
--- a/git-flow-hotfix
+++ b/git-flow-hotfix
@@ -12,8 +12,11 @@
# Copyright (c) 2010 by Benedikt Böhm
#
+gitflow_require_git_repo
+gitflow_require_initialized
+gitflow_load_settings
VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
-PREFIX=$(git config --get gitflow.prefix.hotfix || echo hotfix/)
+PREFIX=$(git config --get gitflow.prefix.hotfix)
usage() {
echo "usage: git flow hotfix [list] [-v]"
@@ -32,7 +35,7 @@
local hotfix_branches
local current_branch
local short_names
- hotfix_branches=$(echo "$LOCAL_BRANCHES" | grep "^$PREFIX")
+ hotfix_branches=$(echo "$(gitflow_local_branches)" | grep "^$PREFIX")
if [ -z "$hotfix_branches" ]; then
warn "No hotfix branches exist."
exit 0
@@ -113,7 +116,7 @@
}
require_no_existing_hotfix_branches() {
- local hotfix_branches=$(echo "$LOCAL_BRANCHES" | grep "^$PREFIX")
+ local hotfix_branches=$(echo "$(gitflow_local_branches)" | grep "^$PREFIX")
local first_branch=$(echo ${hotfix_branches} | head -n1)
first_branch=${first_branch#$PREFIX}
[ -z "$hotfix_branches" ] || \
diff --git a/git-flow-init b/git-flow-init
index 4c43b31..364420a 100644
--- a/git-flow-init
+++ b/git-flow-init
@@ -16,59 +16,219 @@
echo "usage: git flow init"
}
+parse_args() {
+ # parse options
+ FLAGS "$@" || exit $?
+ eval set -- "${FLAGS_ARGV}"
+}
+
# Default entry when no SUBACTION is given
cmd_default() {
- echo
- echo "Summary of actions:"
+ 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 --quiet
- echo "- A new git repository at $PWD was created"
- fi
-
- if ! git rev-parse --quiet --verify HEAD >/dev/null 2>&1; then
- touch "$README"
- git add "$README"
- git commit --quiet -m "initial commit"
- if [ "$MASTER_BRANCH" != "master" ]; then
- git branch -m master "$MASTER_BRANCH"
- fi
- echo "- An initial commit was created at branch '$MASTER_BRANCH'"
- fi
-
- if ! git rev-parse --verify "$MASTER_BRANCH" >/dev/null 2>&1; then
- die "Cannot find your master branch. Try: git branch -m <mymaster> $MASTER_BRANCH"
- fi
-
- gitflow_require_clean_working_tree
-
- if git remote | grep -q "$ORIGIN"; then
- git fetch -q "$ORIGIN"
- gitflow_require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH"
- fi
-
- if git rev-parse --verify "$DEVELOP_BRANCH" >/dev/null 2>&1; then
- gitflow_require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH"
+ git init
else
- git checkout -q -b "$DEVELOP_BRANCH" "$MASTER_BRANCH"
- echo "- A new branch '$DEVELOP_BRANCH' was created"
- echo "- You are now on branch '$DEVELOP_BRANCH'"
+ # assure that we are not working in a repo with local changes
+ git_repo_is_headless || gitflow_require_clean_working_tree
fi
- if ! git remote | grep -q "$ORIGIN"; then
- if [ "$1" = "" ]; then
- echo "- No remote location was added. Try: git remote add $ORIGIN <url>"
+ # 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=$(gitflow_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
- git remote add "$ORIGIN" "$1"
- echo "- A new remote location '$1' was added"
+ echo
+ echo "Which branch should be used for bringing forth production releases?"
+ gitflow_local_branches | sed 's/^.*$/ - &/g'
+
+ should_check_existence=YES
+ default_suggestion=
+ for guess in 'production' 'main' 'master'; do
+ if gitflow_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
+ gitflow_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=$(gitflow_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\"?"
+ gitflow_local_branches | grep -v "^${master_branch}\$" | sed 's/^.*$/ - &/g'
+
+ should_check_existence=YES
+ default_suggestion=
+ for guess in 'develop' 'int' 'integration' 'master'; do
+ if gitflow_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
+ gitflow_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 ! gitflow_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?"
- if git remote | grep -q "$ORIGIN"; then
- git push "$ORIGIN" "$MASTER_BRANCH" "$DEVELOP_BRANCH"
+ 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() {
diff --git a/git-flow-release b/git-flow-release
index 602412e..9aedf3c 100644
--- a/git-flow-release
+++ b/git-flow-release
@@ -12,8 +12,11 @@
# Copyright (c) 2010 by Benedikt Böhm
#
+gitflow_require_git_repo
+gitflow_require_initialized
+gitflow_load_settings
VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
-PREFIX=$(git config --get gitflow.prefix.release || echo release/)
+PREFIX=$(git config --get gitflow.prefix.release)
usage() {
echo "usage: git flow release [list] [-v]"
@@ -43,7 +46,7 @@
local release_branches
local current_branch
local short_names
- release_branches=$(echo "$LOCAL_BRANCHES" | grep "^$PREFIX")
+ release_branches=$(echo "$(gitflow_local_branches)" | grep "^$PREFIX")
if [ -z "$release_branches" ]; then
warn "No release branches exist."
exit 0
@@ -119,7 +122,7 @@
}
require_no_existing_release_branches() {
- local release_branches=$(echo "$LOCAL_BRANCHES" | grep "^$PREFIX")
+ local release_branches=$(echo "$(gitflow_local_branches)" | grep "^$PREFIX")
local first_branch=$(echo ${release_branches} | head -n1)
first_branch=${first_branch#$PREFIX}
[ -z "$release_branches" ] || \
diff --git a/git-flow-support b/git-flow-support
index 804a01d..8a8ac56 100644
--- a/git-flow-support
+++ b/git-flow-support
@@ -12,8 +12,11 @@
# Copyright (c) 2010 by Benedikt Böhm
#
+gitflow_require_git_repo
+gitflow_require_initialized
+gitflow_load_settings
VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag)
-PREFIX=$(git config --get gitflow.prefix.support || echo support/)
+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."
@@ -34,7 +37,7 @@
local support_branches
local current_branch
local short_names
- support_branches=$(echo "$LOCAL_BRANCHES" | grep "^$PREFIX")
+ support_branches=$(echo "$(gitflow_local_branches)" | grep "^$PREFIX")
if [ -z "$support_branches" ]; then
warn "No support branches exist."
exit 0
diff --git a/gitflow-common b/gitflow-common
index 8efc365..9702818 100644
--- a/gitflow-common
+++ b/gitflow-common
@@ -38,11 +38,46 @@
# Git 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" != "" ] && gitflow_local_branch_exists "$master"
+}
+
+gitflow_has_develop_configured() {
+ local develop=$(git config --get gitflow.branch.develop)
+ [ "$develop" != "" ] && gitflow_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
+}
+
# get all available branches
-LOCAL_BRANCHES=$(git branch | sed 's/^[* ] //')
-REMOTE_BRANCHES=$(git branch -r | sed 's/^[* ] //')
-ALL_BRANCHES="$LOCAL_BRANCHES $REMOTE_BRANCHES"
-ALL_TAGS=$(git tag)
+gitflow_local_branches() { git branch | sed 's/^[* ] //'; }
+gitflow_remote_branches() { git branch -r | sed 's/^[* ] //'; }
+gitflow_all_branches() { ( git branch; git branch -r) | sed 's/^[* ] //'; }
+gitflow_all_tags() { git tag; }
+
+# 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)
+}
#
# resolve_nameprefix
@@ -51,8 +86,8 @@
# $1 = name prefix to resolve
# $2 = branch prefix to use
#
-# Searches branch names from LOCAL_BRANCHES to look for a unique branch
-# name whose name starts with the given name prefix.
+# Searches branch names from gitflow_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
@@ -67,12 +102,12 @@
local num_matches
# first, check if there is a perfect match
- if has "$LOCAL_BRANCHES" "$prefix$name"; then
+ if has "$(gitflow_local_branches)" "$prefix$name"; then
echo "$name"
return 0
fi
- matches=$(echo "$LOCAL_BRANCHES" | grep "^$prefix$name")
+ matches=$(echo "$(gitflow_local_branches)" | grep "^$prefix$name")
num_matches=$(echo "$matches" | wc -l)
if [ -z "$matches" ]; then
# no prefix match, so take it literally
@@ -107,6 +142,22 @@
fi
}
+gitflow_require_git_repo() {
+ if ! git rev-parse --git-dir >/dev/null 2>&1; then
+ die "fatal: Not a git repository"
+ fi
+}
+
+gitflow_require_initialized() {
+ if ! gitflow_is_initialized; then
+ die "fatal: Not a gitflow-enabled repo yet. Please run \"git flow init\" first."
+ fi
+}
+
+git_repo_is_headless() {
+ ! git rev-parse --quiet --verify HEAD >/dev/null 2>&1
+}
+
gitflow_require_clean_working_tree() {
gitflow_test_clean_working_tree
local result=$?
@@ -118,40 +169,48 @@
fi
}
+gitflow_local_branch_exists() {
+ has $1 $(gitflow_local_branches)
+}
+
+gitflow_branch_exists() {
+ has $1 $(gitflow_all_branches)
+}
+
+gitflow_tag_exists() {
+ has $1 $(gitflow_all_tags)
+}
+
gitflow_require_local_branch() {
- if ! has $1 $LOCAL_BRANCHES; then
+ if ! gitflow_local_branch_exists; then
die "fatal: Local branch '$1' does not exist and is required."
fi
}
gitflow_require_remote_branch() {
- if ! has $1 $REMOTE_BRANCHES; then
+ if ! has $1 $(gitflow_remote_branches); then
die "Remote branch '$1' does not exist and is required."
fi
}
gitflow_require_branch() {
- if ! has $1 $ALL_BRANCHES; then
+ if ! has $1 $(gitflow_all_branches); then
die "Branch '$1' does not exist and is required."
fi
}
gitflow_require_branch_absent() {
- if has $1 $ALL_BRANCHES; then
+ if has $1 $(gitflow_all_branches); then
die "Branch '$1' already exists. Pick another name."
fi
}
gitflow_require_tag_absent() {
- if has $1 $ALL_TAGS; then
+ if has $1 $(gitflow_all_tags); then
die "Tag '$1' already exists. Pick another name."
fi
}
-gitflow_tag_exists() {
- has $1 $ALL_TAGS
-}
-
#
# gitflow_test_branches_equal()
#
@@ -162,13 +221,16 @@
# 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
#
gitflow_test_branches_equal() {
local commit1=$(git rev-parse "$1")
local commit2=$(git rev-parse "$2")
if [ "$commit1" != "$commit2" ]; then
local base=$(git merge-base "$commit1" "$commit2")
- if [ "$commit1" = "$base" ]; then
+ if [ $? -ne 0 ]; then
+ return 4
+ elif [ "$commit1" = "$base" ]; then
return 1
elif [ "$commit2" = "$base" ]; then
return 2