# # git-flow -- A collection of Git extensions to provide high-level # repository operations for Vincent Driessen's branching model. # # A blog post presenting this model is found at: # http://blog.avirtualhome.com/development-workflow-using-git/ # # Feel free to contribute to this project at: # http://github.com/petervanderdoes/gitflow # # Authors: # Copyright 2012-2015 Peter van der Does. All rights reserved. # # Original Author: # Copyright 2010 Vincent Driessen. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # usage() { OPTIONS_SPEC="\ git flow init Initialize a new git repo with support for the branching model. For more specific help type the command followed by --help -- " flags_help } # Parse arguments and set common variables parse_args() { FLAGS "$@" || exit $? eval set -- "${FLAGS_ARGV}" } # Default entry when no SUBACTION is given cmd_default() { OPTIONS_SPEC="\ git flow init [-h] [-d] [-f] Setup a git repository for git flow usage. Can also be used to start a git repository. -- h,help! Show this help showcommands! Show git commands while executing them d,[no]defaults Use default branch naming conventions f,[no]force Force setting of gitflow branches, even if already configured Use config file location local! use repository config file global! use global config file system! use system config file file= use given config file " local gitflow_config_option should_check_existence branchcount guess local master_branch develop_branch default_suggestion answer prefix # Define flags DEFINE_boolean 'force' false 'force setting of gitflow branches, even if already configured' f DEFINE_boolean 'defaults' false 'use default branch naming conventions' d DEFINE_boolean 'local' false 'use repository config file' DEFINE_boolean 'global' false 'use global config file' DEFINE_boolean 'system' false 'use system config file' DEFINE_string 'file' "" 'use given config file' # Override defaults with values from config gitflow_override_flag_boolean "init.defaults" "defaults" # Parse arguments parse_args "$@" if [ "$FLAGS_file" != "" ]; then gitflow_config_option="--file '$FLAGS_file''" elif flag local; then gitflow_config_option="--local" elif flag global; then gitflow_config_option="--global" elif flag system; then gitflow_config_option="--system" else gitflow_config_option="" fi if ! git rev-parse --git-dir >/dev/null 2>&1; then git_do init else # Assure that we are not working in a repo with local changes git_repo_is_headless || require_clean_working_tree fi # Running git flow init on an already initialized repo is fine if gitflow_is_initialized && ! flag force; then warn "Already initialized for gitflow." warn "To force reinitialization, use: git flow init -f" exit 0 fi if flag defaults; then warn "Using default branch names." fi # Add a master branch if no such branch exists yet if gitflow_has_master_configured && ! flag force; then master_branch=$(git config --get gitflow.branch.master) else # Two cases are distinguished: # 1. A fresh git repo (without any branches) # We will create a new master/develop branch for the user # 2. Some branches do already exist # We will disallow creation of new master/develop branches and # rather allow to use existing branches for git-flow. branch_count=$(git_local_branches | wc -l) if [ "$branch_count" -eq 0 ]; then echo "No branches exist yet. Base branches must be created now." should_check_existence=NO default_suggestion=$(git config --get gitflow.branch.master || echo master) else echo echo "Which branch should be used for bringing forth production releases?" git_local_branches | sed 's/^.*$/ - &/g' should_check_existence=YES default_suggestion= for guess in $(git config --get gitflow.branch.master) 'production' 'main' 'master'; do if git_local_branch_exists "$guess"; then default_suggestion="$guess" break fi done fi if [ -z $default_suggestion ] && flag defaults; then should_check_existence=YES default_suggestion=$(git config --get gitflow.branch.master || echo master) fi printf "Branch name for production releases: [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi master_branch=${answer:-$default_suggestion} # Check existence in case of an already existing repo if [ "$should_check_existence" = "YES" ]; then # If no local branch exists and a remote branch of the same # name exists, checkout that branch and use it for master if ! git_local_branch_exists "$master_branch" && git_remote_branch_exists "origin/$master_branch"; then git_do branch "$master_branch" "origin/$master_branch" >/dev/null 2>&1 elif ! git_local_branch_exists "$master_branch"; then die "Local branch '$master_branch' does not exist." fi fi # Store the name of the master branch git_do config $gitflow_config_option gitflow.branch.master "$master_branch" fi # Add a develop branch if no such branch exists yet if gitflow_has_develop_configured && ! flag force; then develop_branch=$(git config --get gitflow.branch.develop) else # Again, the same two cases as with the master selection are # considered (fresh repo or repo that contains branches) branch_count=$(git_local_branches | grep -v "^${master_branch}\$" | wc -l) if [ "$branch_count" -eq 0 ]; then should_check_existence=NO default_suggestion=$(git config --get gitflow.branch.develop || echo develop) else echo echo "Which branch should be used for integration of the \"next release\"?" git_local_branches | grep -v "^${master_branch}\$" | sed 's/^.*$/ - &/g' should_check_existence=YES default_suggestion= for guess in $(git config --get gitflow.branch.develop) 'develop' 'int' 'integration' 'master'; do if git_local_branch_exists "$guess" && [ "$guess" != "$master_branch" ]; then default_suggestion="$guess" break fi done fi if [ -z $default_suggestion ] && flag defaults; then should_check_existence=YES default_suggestion=$(git config --get gitflow.branch.develop || echo develop) fi printf "Branch name for \"next release\" development: [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi develop_branch=${answer:-$default_suggestion} if [ "$master_branch" = "$develop_branch" ]; then die "Production and integration branches should differ." fi # Check existence in case of an already existing repo if [ "$should_check_existence" = "YES" ]; then git_local_branch_exists "$develop_branch" || die "Local branch '$develop_branch' does not exist." fi # Store the name of the develop branch git_do config $gitflow_config_option gitflow.branch.develop "$develop_branch" fi # Creation of HEAD # ---------------- # We create a HEAD now, if it does not exist yet (in a fresh repo). We need # it to be able to create new branches. local created_gitflow_branch=0 if ! git rev-parse --quiet --verify HEAD >/dev/null 2>&1; then git_do symbolic-ref HEAD "refs/heads/$master_branch" git_do commit --allow-empty --quiet -m "Initial commit" created_gitflow_branch=1 fi # Creation of master # ------------------ # At this point, there always is a master branch: either it existed already # (and was picked interactively as the production branch) or it has just # been created in a fresh repo # Creation of develop # ------------------- # The develop branch possibly does not exist yet. This is the case when, # in a git init'ed repo with one or more commits, master was picked as the # default production branch and develop was "created". We should create # the develop branch now in that case (we base it on master, of course) if ! git_local_branch_exists "$develop_branch"; then if git_remote_branch_exists "origin/$develop_branch"; then git_do branch "$develop_branch" "origin/$develop_branch" >/dev/null 2>&1 else git_do branch --no-track "$develop_branch" "$master_branch" fi created_gitflow_branch=1 fi # Assert the git-flow repo has been correctly initialized gitflow_is_initialized # Switch to develop branch if its newly created if [ $created_gitflow_branch -eq 1 ]; then git_do checkout -q "$develop_branch" || die "Could not check out branch '$develop_branch'." fi # Ask the user for naming conventions (branch and tag prefixes ) if flag force || \ ! git config --get gitflow.prefix.feature >/dev/null 2>&1 || ! git config --get gitflow.prefix.bugfix >/dev/null 2>&1 || ! git config --get gitflow.prefix.release >/dev/null 2>&1 || ! git config --get gitflow.prefix.hotfix >/dev/null 2>&1 || ! git config --get gitflow.prefix.support >/dev/null 2>&1 || ! git config --get gitflow.prefix.versiontag >/dev/null 2>&1; then echo echo "How to name your supporting branch prefixes?" fi # Feature branches if ! git config --get gitflow.prefix.feature >/dev/null 2>&1 || flag force; then default_suggestion=$(git config --get gitflow.prefix.feature || echo feature/) printf "Feature branches? [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} git_do config $gitflow_config_option gitflow.prefix.feature "$prefix" fi # Bugfix branches if ! git config --get gitflow.prefix.bugfix >/dev/null 2>&1 || flag force; then default_suggestion=$(git config --get gitflow.prefix.bugfix || echo bugfix/) printf "Bugfix branches? [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} git_do config $gitflow_config_option gitflow.prefix.bugfix "$prefix" fi # Release branches if ! git config --get gitflow.prefix.release >/dev/null 2>&1 || flag force; then default_suggestion=$(git config --get gitflow.prefix.release || echo release/) printf "Release branches? [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} git_do config $gitflow_config_option gitflow.prefix.release "$prefix" fi # Hotfix branches if ! git config --get gitflow.prefix.hotfix >/dev/null 2>&1 || flag force; then default_suggestion=$(git config --get gitflow.prefix.hotfix || echo hotfix/) printf "Hotfix branches? [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} git_do config $gitflow_config_option gitflow.prefix.hotfix "$prefix" fi # Support branches if ! git config --get gitflow.prefix.support >/dev/null 2>&1 || flag force; then default_suggestion=$(git config --get gitflow.prefix.support || echo support/) printf "Support branches? [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} git_do config $gitflow_config_option gitflow.prefix.support "$prefix" fi # Version tag prefix if ! git config --get gitflow.prefix.versiontag >/dev/null 2>&1 || flag force; then default_suggestion=$(git config --get gitflow.prefix.versiontag || echo "") printf "Version tag prefix? [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} git_do config $gitflow_config_option gitflow.prefix.versiontag "$prefix" fi # Paths if ! git config --get gitflow.path.hooks >/dev/null 2>&1 || flag force; then DOT_GIT_DIR=$(git rev-parse --git-dir) DOT_GIT_DIR=$(cd "$DOT_GIT_DIR" >/dev/null 2>&1 && pwd) default_suggestion=$(git config --get gitflow.path.hooks || echo "$DOT_GIT_DIR"/hooks) printf "Hooks and filters directory? [$default_suggestion] " if noflag defaults; then read answer else printf "\n" fi [ "$answer" = "-" ] && hooks_dir= || hooks_dir=${answer:-$default_suggestion} git_do config $gitflow_config_option gitflow.path.hooks "$hooks_dir" fi # TODO: what to do with origin? } cmd_help() { usage exit 0 }