├── .gitignore ├── .gitmodules ├── AUTHORS ├── Changes.mdown ├── LICENSE ├── Makefile ├── README.mdown ├── TODO ├── bump-version ├── contrib ├── gitflow-installer.sh └── msysgit-install.cmd ├── foo └── foo.txt ├── git-flow ├── git-flow-feature ├── git-flow-hotfix ├── git-flow-init ├── git-flow-release ├── git-flow-support ├── git-flow-version ├── gitflow-common └── gitflow-shFlags /.gitignore: -------------------------------------------------------------------------------- 1 | debian/files 2 | debian/*.substvars 3 | debian/*.debhelper.log 4 | debian/*/* 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "shFlags"] 2 | path = shFlags 3 | url = git://github.com/nvie/shFlags.git 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Authors are (ordered by first commit date): 2 | 3 | - Vincent Driessen 4 | - Benedikt Böhm 5 | - Daniel Truemper 6 | - Jason L. Shiffer 7 | - Randy Merrill 8 | - Rick Osborne 9 | - Mark Derricutt 10 | - Nowell Strite 11 | - Felipe Talavera 12 | - Guillaume-Jean Herbiet 13 | - Joseph A. Levin 14 | - Jannis Leidel 15 | - Konstantin Tjuterev 16 | - Kiall Mac Innes 17 | - Jon Bernard 18 | - Olivier Mengué 19 | - Emre Berge Ergenekon 20 | - Eric Holmes 21 | - Vedang Manerikar 22 | - Myke Hines 23 | 24 | Portions derived from other open source works are clearly marked. 25 | -------------------------------------------------------------------------------- /Changes.mdown: -------------------------------------------------------------------------------- 1 | 0.4.2: 2 | ----- 3 | Release date: **not yet** 4 | 5 | * `git flow init` now detects situations where origin already has gitflow 6 | branches set up, and behaves accordingly (thanks Emre Berge Ergenekon). 7 | 8 | * `git flow feature finish` can now be called without a feature branch 9 | name(prefix) argument and will finish the current branch, if on any. 10 | 11 | * `git flow feature pull` now has a `-r` flag, to support `pull --rebase` 12 | semantics (thanks Vedang Manerikar). 13 | 14 | * Various minor bug fixes related to internal argument passing. 15 | 16 | * Improved some documentation. 17 | 18 | * Better support for Windows and BSD users. 19 | 20 | * Add package installer for the Windows platform. 21 | 22 | 0.4.1: 23 | ----- 24 | Release date: **2011/02/04** 25 | 26 | * New option `-d` added to `git flow init`, to initialize with defaults without 27 | asking for input interactively. Ideal for creating git-flow enabled repos in 28 | custom scripts. 29 | 30 | * The parsing issues related to git-flow feature's flags are now dealt with on 31 | all known platforms. (Fixed #54, #62, #86, #97) 32 | 33 | * Escape queries for detecting branch/tag names. (Fixed #91) 34 | 35 | 36 | 0.4: 37 | --- 38 | Release date: **2010/10/18** 39 | 40 | * The flag parsing issues of git-flow subcommands are solved for most 41 | platforms. 42 | 43 | * `git flow {feature,hotfix,release} finish` now takes a `-k` flag, to keep the 44 | branch around after finishing. 45 | 46 | * `git flow release finish` takes a `-n` flag, to skip tagging. 47 | 48 | * For consistency, `git flow {release,hotfix}` now, too, have a `publish` and 49 | `track` subcommand, just like `feature`. 50 | 51 | * Various minor fixes. 52 | 53 | 54 | 0.3: 55 | ---- 56 | Release date: **2010/07/22** 57 | 58 | * New subcommands for `git flow feature`: 59 | - **checkout**: 60 | For easily checking out features by their short name. Even allows 61 | unique prefixes as arguments (see below). 62 | 63 | - **pull**: 64 | This subcommand allows you to painlessly work on a feature branch 65 | together with another peer. This is especially valuable for doing 66 | peer reviews of other people's code. For more detailed info, see the 67 | [commit log][1]. 68 | 69 | * Easier addressing of branch names by using name prefixes. 70 | For example, when using: 71 | 72 | git flow feature finish fo 73 | 74 | this automatically finishes the feature branch `foobar` if that's the only 75 | feature branch name starting with `fo`. 76 | 77 | * No force flag anymore for new feature branches 78 | `git flow feature start` lost its `-f` (force) flag. You now don't 79 | have to be in a clean repo anymore to start a new feature branch. This 80 | avoids the manual `git stash`, `git flow feature start`, `git stash 81 | pop` cycle. 82 | 83 | * You can use `git-flow` in stand-alone repo's now. 84 | This means it does not assume you have an `origin` repository. 85 | (Thanks [Mark][2].) 86 | 87 | * No commands fetch from `origin` by default anymore. 88 | There were some issues related to disabling this flag on some platforms. 89 | 90 | * Init guesses branch names you may want to use for `develop` and `master`. 91 | 92 | * Added super-easy installation script. (Thanks [Rick][3].) 93 | 94 | * Added BSD license. 95 | 96 | [1]: http://github.com/nvie/gitflow/commit/f68d405cc3a11e9df3671f567658a6ab6ed8e0a1 97 | [2]: http://github.com/talios 98 | [3]: http://github.com/rickosborne 99 | 100 | 101 | Older versions 102 | -------------- 103 | No change history is recorded for pre-0.3 releases. 104 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010 Vincent Driessen. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 14 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 15 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 16 | SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 18 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 20 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 21 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of Vincent Driessen. 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Vincent Driessen. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, 8 | # this list of conditions and the following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above copyright 11 | # notice, this list of conditions and the following disclaimer in the 12 | # documentation and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 15 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 22 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 23 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | # 25 | # The views and conclusions contained in the software and documentation are 26 | # those of the authors and should not be interpreted as representing official 27 | # policies, either expressed or implied, of Vincent Driessen. 28 | # 29 | 30 | prefix=/usr/local 31 | 32 | # files that need mode 755 33 | EXEC_FILES=git-flow 34 | 35 | # files that need mode 644 36 | SCRIPT_FILES =git-flow-init 37 | SCRIPT_FILES+=git-flow-feature 38 | SCRIPT_FILES+=git-flow-hotfix 39 | SCRIPT_FILES+=git-flow-release 40 | SCRIPT_FILES+=git-flow-support 41 | SCRIPT_FILES+=git-flow-version 42 | SCRIPT_FILES+=gitflow-common 43 | SCRIPT_FILES+=gitflow-shFlags 44 | 45 | all: 46 | @echo "usage: make install" 47 | @echo " make uninstall" 48 | 49 | install: 50 | @test -f gitflow-shFlags || (echo "Run 'git submodule init && git submodule update' first." ; exit 1 ) 51 | install -d -m 0755 $(prefix)/bin 52 | install -m 0755 $(EXEC_FILES) $(prefix)/bin 53 | install -m 0644 $(SCRIPT_FILES) $(prefix)/bin 54 | 55 | uninstall: 56 | test -d $(prefix)/bin && \ 57 | cd $(prefix)/bin && \ 58 | rm -f $(EXEC_FILES) $(SCRIPT_FILES) 59 | -------------------------------------------------------------------------------- /README.mdown: -------------------------------------------------------------------------------- 1 | git-flow 2 | ======== 3 | 4 | A collection of Git extensions to provide high-level repository operations 5 | for Vincent Driessen's [branching model](http://nvie.com/git-model "original 6 | blog post"). 7 | 8 | 9 | Getting started 10 | --------------- 11 | For the best introduction to get started with `git flow`, please read Jeff 12 | Kreeftmeijer's blog post: 13 | 14 | [http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/](http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/) 15 | 16 | Or have a look at one of these screen casts: 17 | 18 | * [How to use a scalable Git branching model called git-flow](http://buildamodule.com/video/change-management-and-version-control-deploying-releases-features-and-fixes-with-git-how-to-use-a-scalable-git-branching-model-called-gitflow) (by Build a Module) 19 | * [A short introduction to git-flow](http://vimeo.com/16018419) (by Mark Derricutt) 20 | * [On the path with git-flow](http://codesherpas.com/screencasts/on_the_path_gitflow.mov) (by Dave Bock) 21 | 22 | 23 | Installing git-flow 24 | ------------------- 25 | See the Wiki for up-to-date [Installation Instructions](https://github.com/nvie/gitflow/wiki/Installation). 26 | 27 | 28 | Integration with your shell 29 | --------------------------- 30 | For those who use the [Bash](http://www.gnu.org/software/bash/) or 31 | [ZSH](http://www.zsh.org) shell, please check out the excellent work on the 32 | [git-flow-completion](http://github.com/bobthecow/git-flow-completion) project 33 | by [bobthecow](http://github.com/bobthecow). It offers tab-completion for all 34 | git-flow subcommands and branch names. 35 | 36 | 37 | FAQ 38 | --- 39 | See the [FAQ](http://github.com/nvie/gitflow/wiki/FAQ) section of the project 40 | Wiki. 41 | 42 | 43 | Please help out 44 | --------------- 45 | This project is still under development. Feedback and suggestions are very 46 | welcome and I encourage you to use the [Issues 47 | list](http://github.com/nvie/gitflow/issues) on Github to provide that 48 | feedback. 49 | 50 | Feel free to fork this repo and to commit your additions. For a list of all 51 | contributors, please see the [AUTHORS](AUTHORS) file. 52 | 53 | Any questions, tips, or general discussion can be posted to our Google group: 54 | [http://groups.google.com/group/gitflow-users](http://groups.google.com/group/gitflow-users) 55 | 56 | Contributing 57 | ------------ 58 | Fork the repository. Then, run: 59 | 60 | git clone --recursive git@github.com:/gitflow.git 61 | cd gitflow 62 | git branch master origin/master 63 | git flow init -d 64 | git flow feature start 65 | 66 | Then, do work and commit your changes. **Hint**: ``export PATH=`pwd`:$PATH`` 67 | from within the gitflow directory makes sure you're using the version of 68 | gitflow you're currently developing. 69 | 70 | git flow feature publish 71 | 72 | When done, open a pull request to your feature branch. 73 | 74 | License terms 75 | ------------- 76 | git-flow is published under the liberal terms of the BSD License, see the 77 | [LICENSE](LICENSE) file. Although the BSD License does not require you to share 78 | any modifications you make to the source code, you are very much encouraged and 79 | invited to contribute back your modifications to the community, preferably 80 | in a Github fork, of course. 81 | 82 | 83 | ### Initialization 84 | 85 | To initialize a new repo with the basic branch structure, use: 86 | 87 | git flow init [-d] 88 | 89 | This will then interactively prompt you with some questions on which branches 90 | you would like to use as development and production branches, and how you 91 | would like your prefixes be named. You may simply press Return on any of 92 | those questions to accept the (sane) default suggestions. 93 | 94 | The ``-d`` flag will accept all defaults. 95 | 96 | 97 | ### Creating feature/release/hotfix/support branches 98 | 99 | * To list/start/finish feature branches, use: 100 | 101 | git flow feature 102 | git flow feature start [] 103 | git flow feature finish 104 | 105 | For feature branches, the `` arg must be a commit on `develop`. 106 | 107 | * To push/pull a feature branch to the remote repository, use: 108 | 109 | git flow feature publish 110 | git flow feature pull 111 | 112 | * To list/start/finish release branches, use: 113 | 114 | git flow release 115 | git flow release start [] 116 | git flow release finish 117 | 118 | For release branches, the `` arg must be a commit on `develop`. 119 | 120 | * To list/start/finish hotfix branches, use: 121 | 122 | git flow hotfix 123 | git flow hotfix start [] 124 | git flow hotfix finish 125 | 126 | For hotfix branches, the `` arg must be a commit on `master`. 127 | 128 | * To list/start support branches, use: 129 | 130 | git flow support 131 | git flow support start 132 | 133 | For support branches, the `` arg must be a commit on `master`. 134 | 135 | 136 | Showing your appreciation 137 | ========================= 138 | A few people already requested it, so now it's here: a Flattr button. 139 | 140 | Of course, the best way to show your appreciation for the original 141 | [blog post](http://nvie.com/posts/a-successful-git-branching-model/) or the git-flow tool itself remains 142 | contributing to the community. If you'd like to show your appreciation in 143 | another way, however, consider Flattr'ing me: 144 | 145 | [![Flattr this][2]][1] 146 | 147 | [1]: http://flattr.com/thing/53771/git-flow 148 | [2]: http://api.flattr.com/button/button-static-50x60.png 149 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | TODO from develop 2 | -------------------------------------------------------------------------------- /bump-version: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | usage() { 3 | echo "usage: bump-version " 4 | } 5 | 6 | if [ $# -ne 1 ]; then 7 | usage 8 | exit 1 9 | fi 10 | 11 | if ! sed 's/^GITFLOW_VERSION=.*$/GITFLOW_VERSION='$1'/g' git-flow-version > .git-flow-version.new; then 12 | echo "Could not replace GITFLOW_VERSION variable." >&2 13 | exit 2 14 | fi 15 | 16 | mv .git-flow-version.new git-flow-version 17 | git add git-flow-version 18 | git commit -m "Bumped version number to $1" git-flow-version 19 | -------------------------------------------------------------------------------- /contrib/gitflow-installer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # git-flow make-less installer for *nix systems, by Rick Osborne 4 | # Based on the git-flow core Makefile: 5 | # http://github.com/nvie/gitflow/blob/master/Makefile 6 | 7 | # Licensed under the same restrictions as git-flow: 8 | # http://github.com/nvie/gitflow/blob/develop/LICENSE 9 | 10 | # Does this need to be smarter for each host OS? 11 | if [ -z "$INSTALL_PREFIX" ] ; then 12 | INSTALL_PREFIX="/usr/local/bin" 13 | fi 14 | 15 | if [ -z "$REPO_NAME" ] ; then 16 | REPO_NAME="gitflow" 17 | fi 18 | 19 | if [ -z "$REPO_HOME" ] ; then 20 | REPO_HOME="http://github.com/nvie/gitflow.git" 21 | fi 22 | 23 | EXEC_FILES="git-flow" 24 | SCRIPT_FILES="git-flow-init git-flow-feature git-flow-hotfix git-flow-release git-flow-support git-flow-version gitflow-common gitflow-shFlags" 25 | SUBMODULE_FILE="gitflow-shFlags" 26 | 27 | echo "### gitflow no-make installer ###" 28 | 29 | case "$1" in 30 | uninstall) 31 | echo "Uninstalling git-flow from $INSTALL_PREFIX" 32 | if [ -d "$INSTALL_PREFIX" ] ; then 33 | for script_file in $SCRIPT_FILES $EXEC_FILES ; do 34 | echo "rm -vf $INSTALL_PREFIX/$script_file" 35 | rm -vf "$INSTALL_PREFIX/$script_file" 36 | done 37 | else 38 | echo "The '$INSTALL_PREFIX' directory was not found." 39 | echo "Do you need to set INSTALL_PREFIX ?" 40 | fi 41 | exit 42 | ;; 43 | help) 44 | echo "Usage: [environment] gitflow-installer.sh [install|uninstall]" 45 | echo "Environment:" 46 | echo " INSTALL_PREFIX=$INSTALL_PREFIX" 47 | echo " REPO_HOME=$REPO_HOME" 48 | echo " REPO_NAME=$REPO_NAME" 49 | exit 50 | ;; 51 | *) 52 | echo "Installing git-flow to $INSTALL_PREFIX" 53 | if [ -d "$REPO_NAME" -a -d "$REPO_NAME/.git" ] ; then 54 | echo "Using existing repo: $REPO_NAME" 55 | else 56 | echo "Cloning repo from GitHub to $REPO_NAME" 57 | git clone "$REPO_HOME" "$REPO_NAME" 58 | fi 59 | if [ -f "$REPO_NAME/$SUBMODULE_FILE" ] ; then 60 | echo "Submodules look up to date" 61 | else 62 | echo "Updating submodules" 63 | lastcwd=$PWD 64 | cd "$REPO_NAME" 65 | git submodule init 66 | git submodule update 67 | cd "$lastcwd" 68 | fi 69 | install -v -d -m 0755 "$INSTALL_PREFIX" 70 | for exec_file in $EXEC_FILES ; do 71 | install -v -m 0755 "$REPO_NAME/$exec_file" "$INSTALL_PREFIX" 72 | done 73 | for script_file in $SCRIPT_FILES ; do 74 | install -v -m 0644 "$REPO_NAME/$script_file" "$INSTALL_PREFIX" 75 | done 76 | exit 77 | ;; 78 | esac 79 | -------------------------------------------------------------------------------- /contrib/msysgit-install.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | if not "%~1"=="" set GIT_HOME=%~f1 4 | if "%GIT_HOME%"=="" call :FindGitHome "git.cmd" 5 | 6 | if exist "%GIT_HOME%" goto :GitHomeOK 7 | 8 | echo MsysGit installation directory not found.>&2 9 | echo Try to give the directory name on the command line:>&2 10 | echo %0 "%ProgramFiles%\Git" 11 | endlocal 12 | exit /B 1 13 | 14 | :GitHomeOK 15 | set ERR=0 16 | 17 | echo Installing gitflow into "%GIT_HOME%"... 18 | 19 | call :ChkGetopt getopt.exe || set ERR=1 20 | if %ERR%==1 goto :End 21 | echo getopt.exe... Found 22 | 23 | if not exist "%GIT_HOME%\bin\git-flow" goto :Install 24 | echo GitFlow is already installed.>&2 25 | set /p mychoice="Do you want to replace it [y/n]" 26 | if "%mychoice%"=="y" goto :DeleteOldFiles 27 | goto :Abort 28 | 29 | :DeleteOldFiles 30 | echo Deleting old files... 31 | for /F %%i in ("%GIT_HOME%\git-flow*" "%GIT_HOME%\gitflow-*") do if exist "%%~fi" del /F /Q "%%~fi" 32 | 33 | :Install 34 | echo Copying files... 35 | ::goto :EOF 36 | xcopy "%~dp0\..\git-flow" "%GIT_HOME%\bin" /Y /R /F 37 | if errorlevel 4 if not errorlevel 5 goto :AccessDenied 38 | if errorlevel 1 set ERR=1 39 | xcopy "%~dp0\..\git-flow*" "%GIT_HOME%\bin" /Y /R /F || set ERR=1 40 | xcopy "%~dp0\..\gitflow-*" "%GIT_HOME%\bin" /Y /R /F || set ERR=1 41 | xcopy "%~dp0\..\shFlags\src\shflags" "%GIT_HOME%\bin\gitflow-shFlags" /Y /R /F || set ERR=1 42 | 43 | if %ERR%==1 choice /T 30 /C Y /D Y /M "Some unexpected errors happened. Sorry, you'll have to fix them by yourself." 44 | 45 | :End 46 | endlocal & exit /B %ERR% 47 | goto :EOF 48 | 49 | :AccessDenied 50 | set ERR=1 51 | echo. 52 | echo You should run this script with "Full Administrator" rights:>&2 53 | echo - Right-click with Shift on the script from the Explorer>&2 54 | echo - Select "Run as administrator">&2 55 | choice /T 30 /C YN /D Y /N >nul 56 | goto :End 57 | 58 | :Abort 59 | echo Installation canceled.>&2 60 | set ERR=1 61 | goto :End 62 | 63 | :ChkGetopt 64 | :: %1 is getopt.exe 65 | if exist "%GIT_HOME%\bin\%1" goto :EOF 66 | if exist "%USERPROFILE%\bin\%1" goto :EOF 67 | if exist "%~f$PATH:1" goto :EOF 68 | echo %GIT_HOME%\bin\%1 not found.>&2 69 | echo You have to install this file manually. See the GitFlow README. 70 | exit /B 1 71 | 72 | :FindGitHome 73 | setlocal 74 | set GIT_CMD_DIR=%~dp$PATH:1 75 | if "%GIT_CMD_DIR%"=="" endlocal & goto :EOF 76 | endlocal & set GIT_HOME=%GIT_CMD_DIR:~0,-5% 77 | goto :EOF 78 | -------------------------------------------------------------------------------- /foo/foo.txt: -------------------------------------------------------------------------------- 1 | The quick brown fox jumps over the lazy dog. 2 | -------------------------------------------------------------------------------- /git-flow: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # git-flow -- A collection of Git extensions to provide high-level 4 | # repository operations for Vincent Driessen's branching model. 5 | # 6 | # Original blog post presenting this model is found at: 7 | # http://nvie.com/git-model 8 | # 9 | # Feel free to contribute to this project at: 10 | # http://github.com/nvie/gitflow 11 | # 12 | # Copyright 2010 Vincent Driessen. All rights reserved. 13 | # 14 | # Redistribution and use in source and binary forms, with or without 15 | # modification, are permitted provided that the following conditions are met: 16 | # 17 | # 1. Redistributions of source code must retain the above copyright notice, 18 | # this list of conditions and the following disclaimer. 19 | # 20 | # 2. Redistributions in binary form must reproduce the above copyright 21 | # notice, this list of conditions and the following disclaimer in the 22 | # documentation and/or other materials provided with the distribution. 23 | # 24 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 25 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 27 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 28 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 31 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 33 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | # 35 | # The views and conclusions contained in the software and documentation are 36 | # those of the authors and should not be interpreted as representing official 37 | # policies, either expressed or implied, of Vincent Driessen. 38 | # 39 | 40 | # set this to workaround expr problems in shFlags on freebsd 41 | if uname -s | egrep -iq 'bsd'; then export EXPR_COMPAT=1; fi 42 | 43 | # enable debug mode 44 | if [ "$DEBUG" = "yes" ]; then 45 | set -x 46 | fi 47 | 48 | # The sed expression here replaces all backslashes by forward slashes. 49 | # This helps our Windows users, while not bothering our Unix users. 50 | export GITFLOW_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") 51 | 52 | usage() { 53 | echo "usage: git flow " 54 | echo 55 | echo "Available subcommands are:" 56 | echo " init Initialize a new git repo with support for the branching model." 57 | echo " feature Manage your feature branches." 58 | echo " release Manage your release branches." 59 | echo " hotfix Manage your hotfix branches." 60 | echo " support Manage your support branches." 61 | echo " version Shows version information." 62 | echo 63 | echo "Try 'git flow help' for details." 64 | } 65 | 66 | main() { 67 | if [ $# -lt 1 ]; then 68 | usage 69 | exit 1 70 | fi 71 | 72 | # load common functionality 73 | . "$GITFLOW_DIR/gitflow-common" 74 | 75 | # This environmental variable fixes non-POSIX getopt style argument 76 | # parsing, effectively breaking git-flow subcommand parsing on several 77 | # Linux platforms. 78 | export POSIXLY_CORRECT=1 79 | 80 | # use the shFlags project to parse the command line arguments 81 | . "$GITFLOW_DIR/gitflow-shFlags" 82 | FLAGS_PARENT="git flow" 83 | 84 | # allow user to request git action logging 85 | DEFINE_boolean show_commands false 'show actions taken (git commands)' g 86 | 87 | # do actual parsing 88 | FLAGS "$@" || exit $? 89 | eval set -- "${FLAGS_ARGV}" 90 | 91 | # sanity checks 92 | SUBCOMMAND="$1"; shift 93 | 94 | if [ ! -e "$GITFLOW_DIR/git-flow-$SUBCOMMAND" ]; then 95 | usage 96 | exit 1 97 | fi 98 | 99 | # run command 100 | . "$GITFLOW_DIR/git-flow-$SUBCOMMAND" 101 | FLAGS_PARENT="git flow $SUBCOMMAND" 102 | 103 | # test if the first argument is a flag (i.e. starts with '-') 104 | # in that case, we interpret this arg as a flag for the default 105 | # command 106 | SUBACTION="default" 107 | if [ "$1" != "" ] && { ! echo "$1" | grep -q "^-"; } then 108 | SUBACTION="$1"; shift 109 | fi 110 | if ! type "cmd_$SUBACTION" >/dev/null 2>&1; then 111 | warn "Unknown subcommand: '$SUBACTION'" 112 | usage 113 | exit 1 114 | fi 115 | 116 | # run the specified action 117 | if [ $SUBACTION != "help" ] && [ $SUBCOMMAND != "init" ] ; then 118 | init 119 | fi 120 | cmd_$SUBACTION "$@" 121 | } 122 | 123 | main "$@" 124 | -------------------------------------------------------------------------------- /git-flow-feature: -------------------------------------------------------------------------------- 1 | # 2 | # git-flow -- A collection of Git extensions to provide high-level 3 | # repository operations for Vincent Driessen's branching model. 4 | # 5 | # Original blog post presenting this model is found at: 6 | # http://nvie.com/git-model 7 | # 8 | # Feel free to contribute to this project at: 9 | # http://github.com/nvie/gitflow 10 | # 11 | # Copyright 2010 Vincent Driessen. All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or without 14 | # modification, are permitted provided that the following conditions are met: 15 | # 16 | # 1. Redistributions of source code must retain the above copyright notice, 17 | # this list of conditions and the following disclaimer. 18 | # 19 | # 2. Redistributions in binary form must reproduce the above copyright 20 | # notice, this list of conditions and the following disclaimer in the 21 | # documentation and/or other materials provided with the distribution. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 24 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 26 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 30 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 32 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | # 34 | # The views and conclusions contained in the software and documentation are 35 | # those of the authors and should not be interpreted as representing official 36 | # policies, either expressed or implied, of Vincent Driessen. 37 | # 38 | 39 | init() { 40 | require_git_repo 41 | require_gitflow_initialized 42 | gitflow_load_settings 43 | PREFIX=$(git config --get gitflow.prefix.feature) 44 | } 45 | 46 | usage() { 47 | echo "usage: git flow feature [list] [-v]" 48 | echo " git flow feature start [-F] []" 49 | echo " git flow feature finish [-rFkDS] []" 50 | echo " git flow feature publish " 51 | echo " git flow feature track " 52 | echo " git flow feature diff []" 53 | echo " git flow feature rebase [-i] []" 54 | echo " git flow feature checkout []" 55 | echo " git flow feature pull [-r] []" 56 | } 57 | 58 | cmd_default() { 59 | cmd_list "$@" 60 | } 61 | 62 | cmd_list() { 63 | DEFINE_boolean verbose false 'verbose (more) output' v 64 | parse_args "$@" 65 | 66 | local feature_branches 67 | local current_branch 68 | local short_names 69 | feature_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX") 70 | if [ -z "$feature_branches" ]; then 71 | warn "No feature branches exist." 72 | warn "" 73 | warn "You can start a new feature branch:" 74 | warn "" 75 | warn " git flow feature start []" 76 | warn "" 77 | exit 0 78 | fi 79 | current_branch=$(git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g') 80 | short_names=$(echo "$feature_branches" | sed "s ^$PREFIX g") 81 | 82 | # determine column width first 83 | local width=0 84 | local branch 85 | for branch in $short_names; do 86 | local len=${#branch} 87 | width=$(max $width $len) 88 | done 89 | width=$(($width+3)) 90 | 91 | local branch 92 | for branch in $short_names; do 93 | local fullname=$PREFIX$branch 94 | local base=$(git merge-base "$fullname" "$DEVELOP_BRANCH") 95 | local develop_sha=$(git rev-parse "$DEVELOP_BRANCH") 96 | local branch_sha=$(git rev-parse "$fullname") 97 | if [ "$fullname" = "$current_branch" ]; then 98 | printf "* " 99 | else 100 | printf " " 101 | fi 102 | if flag verbose; then 103 | printf "%-${width}s" "$branch" 104 | if [ "$branch_sha" = "$develop_sha" ]; then 105 | printf "(no commits yet)" 106 | elif [ "$base" = "$branch_sha" ]; then 107 | printf "(is behind develop, may ff)" 108 | elif [ "$base" = "$develop_sha" ]; then 109 | printf "(based on latest develop)" 110 | else 111 | printf "(may be rebased)" 112 | fi 113 | else 114 | printf "%s" "$branch" 115 | fi 116 | echo 117 | done 118 | } 119 | 120 | cmd_help() { 121 | usage 122 | exit 0 123 | } 124 | 125 | require_name_arg() { 126 | if [ "$NAME" = "" ]; then 127 | warn "Missing argument " 128 | usage 129 | exit 1 130 | fi 131 | } 132 | 133 | expand_nameprefix_arg() { 134 | require_name_arg 135 | 136 | local expanded_name 137 | local exitcode 138 | expanded_name=$(gitflow_resolve_nameprefix "$NAME" "$PREFIX") 139 | exitcode=$? 140 | case $exitcode in 141 | 0) NAME=$expanded_name 142 | BRANCH=$PREFIX$NAME 143 | ;; 144 | *) exit 1 ;; 145 | esac 146 | } 147 | 148 | use_current_feature_branch_name() { 149 | local current_branch=$(git_current_branch) 150 | if startswith "$current_branch" "$PREFIX"; then 151 | BRANCH=$current_branch 152 | NAME=${BRANCH#$PREFIX} 153 | else 154 | warn "The current HEAD is no feature branch." 155 | warn "Please specify a argument." 156 | exit 1 157 | fi 158 | } 159 | 160 | expand_nameprefix_arg_or_current() { 161 | if [ "$NAME" != "" ]; then 162 | expand_nameprefix_arg 163 | require_branch "$PREFIX$NAME" 164 | else 165 | use_current_feature_branch_name 166 | fi 167 | } 168 | 169 | name_or_current() { 170 | if [ -z "$NAME" ]; then 171 | use_current_feature_branch_name 172 | fi 173 | } 174 | 175 | parse_args() { 176 | # parse options 177 | FLAGS "$@" || exit $? 178 | eval set -- "${FLAGS_ARGV}" 179 | 180 | # read arguments into global variables 181 | NAME=$1 182 | BRANCH=$PREFIX$NAME 183 | } 184 | 185 | parse_remote_name() { 186 | # parse options 187 | FLAGS "$@" || exit $? 188 | eval set -- "${FLAGS_ARGV}" 189 | 190 | # read arguments into global variables 191 | REMOTE=$1 192 | NAME=$2 193 | BRANCH=$PREFIX$NAME 194 | } 195 | 196 | cmd_start() { 197 | DEFINE_boolean fetch false 'fetch from origin before performing local operation' F 198 | parse_args "$@" 199 | BASE=${2:-$DEVELOP_BRANCH} 200 | require_name_arg 201 | 202 | # sanity checks 203 | require_branch_absent "$BRANCH" 204 | 205 | # update the local repo with remote changes, if asked 206 | if flag fetch; then 207 | git_do fetch -q "$ORIGIN" "$DEVELOP_BRANCH" 208 | fi 209 | 210 | # if the origin branch counterpart exists, assert that the local branch 211 | # isn't behind it (to avoid unnecessary rebasing) 212 | if git_branch_exists "$ORIGIN/$DEVELOP_BRANCH"; then 213 | require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH" 214 | fi 215 | 216 | # create branch 217 | if ! git_do checkout -b "$BRANCH" "$BASE"; then 218 | die "Could not create feature branch '$BRANCH'" 219 | fi 220 | 221 | echo 222 | echo "Summary of actions:" 223 | echo "- A new branch '$BRANCH' was created, based on '$BASE'" 224 | echo "- You are now on branch '$BRANCH'" 225 | echo "" 226 | echo "Now, start committing on your feature. When done, use:" 227 | echo "" 228 | echo " git flow feature finish $NAME" 229 | echo 230 | } 231 | 232 | cmd_finish() { 233 | DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F 234 | DEFINE_boolean rebase false "rebase instead of merge" r 235 | DEFINE_boolean keep false "keep branch after performing finish" k 236 | DEFINE_boolean force_delete false "force delete feature branch after finish" D 237 | DEFINE_boolean squash false "squash feature during merge" S 238 | parse_args "$@" 239 | expand_nameprefix_arg_or_current 240 | 241 | # sanity checks 242 | require_branch "$BRANCH" 243 | 244 | # detect if we're restoring from a merge conflict 245 | if [ -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE" ]; then 246 | # 247 | # TODO: detect that we're working on the correct branch here! 248 | # The user need not necessarily have given the same $NAME twice here 249 | # (although he/she should). 250 | # 251 | 252 | # TODO: git_is_clean_working_tree() should provide an alternative 253 | # exit code for "unmerged changes in working tree", which we should 254 | # actually be testing for here 255 | if git_is_clean_working_tree; then 256 | FINISH_BASE=$(cat "$DOT_GIT_DIR/.gitflow/MERGE_BASE") 257 | 258 | # Since the working tree is now clean, either the user did a 259 | # succesfull merge manually, or the merge was cancelled. 260 | # We detect this using git_is_branch_merged_into() 261 | if git_is_branch_merged_into "$BRANCH" "$FINISH_BASE"; then 262 | rm -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE" 263 | helper_finish_cleanup 264 | exit 0 265 | else 266 | # If the user cancelled the merge and decided to wait until later, 267 | # that's fine. But we have to acknowledge this by removing the 268 | # MERGE_BASE file and continuing normal execution of the finish 269 | rm -f "$DOT_GIT_DIR/.gitflow/MERGE_BASE" 270 | fi 271 | else 272 | echo 273 | echo "Merge conflicts not resolved yet, use:" 274 | echo " git mergetool" 275 | echo " git commit" 276 | echo 277 | echo "You can then complete the finish by running it again:" 278 | echo " git flow feature finish $NAME" 279 | echo 280 | exit 1 281 | fi 282 | fi 283 | 284 | # sanity checks 285 | require_clean_working_tree 286 | 287 | # update local repo with remote changes first, if asked 288 | if has "$ORIGIN/$BRANCH" $(git_remote_branches); then 289 | if flag fetch; then 290 | git_do fetch -q "$ORIGIN" "$BRANCH" 291 | git_do fetch -q "$ORIGIN" "$DEVELOP_BRANCH" 292 | fi 293 | fi 294 | 295 | if has "$ORIGIN/$BRANCH" $(git_remote_branches); then 296 | require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH" 297 | fi 298 | if has "$ORIGIN/$DEVELOP_BRANCH" $(git_remote_branches); then 299 | require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH" 300 | fi 301 | 302 | # if the user wants to rebase, do that first 303 | if flag rebase; then 304 | if ! git flow feature rebase "$NAME" "$DEVELOP_BRANCH"; then 305 | warn "Finish was aborted due to conflicts during rebase." 306 | warn "Please finish the rebase manually now." 307 | warn "When finished, re-run:" 308 | warn " git flow feature finish '$NAME' '$DEVELOP_BRANCH'" 309 | exit 1 310 | fi 311 | fi 312 | 313 | # merge into BASE 314 | git_do checkout "$DEVELOP_BRANCH" 315 | if [ "$(git rev-list -n2 "$DEVELOP_BRANCH..$BRANCH" | wc -l)" -eq 1 ]; then 316 | git_do merge --ff "$BRANCH" 317 | else 318 | if noflag squash; then 319 | git_do merge --no-ff "$BRANCH" 320 | else 321 | git_do merge --squash "$BRANCH" 322 | git_do commit 323 | git_do merge "$BRANCH" 324 | fi 325 | fi 326 | 327 | if [ $? -ne 0 ]; then 328 | # oops.. we have a merge conflict! 329 | # write the given $DEVELOP_BRANCH to a temporary file (we need it later) 330 | mkdir -p "$DOT_GIT_DIR/.gitflow" 331 | echo "$DEVELOP_BRANCH" > "$DOT_GIT_DIR/.gitflow/MERGE_BASE" 332 | echo 333 | echo "There were merge conflicts. To resolve the merge conflict manually, use:" 334 | echo " git mergetool" 335 | echo " git commit" 336 | echo 337 | echo "You can then complete the finish by running it again:" 338 | echo " git flow feature finish $NAME" 339 | echo 340 | exit 1 341 | fi 342 | 343 | # when no merge conflict is detected, just clean up the feature branch 344 | helper_finish_cleanup 345 | } 346 | 347 | helper_finish_cleanup() { 348 | # sanity checks 349 | require_branch "$BRANCH" 350 | require_clean_working_tree 351 | 352 | # delete branch 353 | if flag fetch; then 354 | git_do push "$ORIGIN" ":refs/heads/$BRANCH" 355 | fi 356 | 357 | 358 | if noflag keep; then 359 | if flag force_delete; then 360 | git_do branch -D "$BRANCH" 361 | else 362 | git_do branch -d "$BRANCH" 363 | fi 364 | fi 365 | 366 | echo 367 | echo "Summary of actions:" 368 | echo "- The feature branch '$BRANCH' was merged into '$DEVELOP_BRANCH'" 369 | #echo "- Merge conflicts were resolved" # TODO: Add this line when it's supported 370 | if flag keep; then 371 | echo "- Feature branch '$BRANCH' is still available" 372 | else 373 | echo "- Feature branch '$BRANCH' has been removed" 374 | fi 375 | echo "- You are now on branch '$DEVELOP_BRANCH'" 376 | echo 377 | } 378 | 379 | cmd_publish() { 380 | parse_args "$@" 381 | expand_nameprefix_arg 382 | 383 | # sanity checks 384 | require_clean_working_tree 385 | require_branch "$BRANCH" 386 | git_do fetch -q "$ORIGIN" 387 | require_branch_absent "$ORIGIN/$BRANCH" 388 | 389 | # create remote branch 390 | git_do push "$ORIGIN" "$BRANCH:refs/heads/$BRANCH" 391 | git_do fetch -q "$ORIGIN" 392 | 393 | # configure remote tracking 394 | git_do config "branch.$BRANCH.remote" "$ORIGIN" 395 | git_do config "branch.$BRANCH.merge" "refs/heads/$BRANCH" 396 | git_do checkout "$BRANCH" 397 | 398 | echo 399 | echo "Summary of actions:" 400 | echo "- A new remote branch '$BRANCH' was created" 401 | echo "- The local branch '$BRANCH' was configured to track the remote branch" 402 | echo "- You are now on branch '$BRANCH'" 403 | echo 404 | } 405 | 406 | cmd_track() { 407 | parse_args "$@" 408 | require_name_arg 409 | 410 | # sanity checks 411 | require_clean_working_tree 412 | require_branch_absent "$BRANCH" 413 | git_do fetch -q "$ORIGIN" 414 | require_branch "$ORIGIN/$BRANCH" 415 | 416 | # create tracking branch 417 | git_do checkout -b "$BRANCH" "$ORIGIN/$BRANCH" 418 | 419 | echo 420 | echo "Summary of actions:" 421 | echo "- A new remote tracking branch '$BRANCH' was created" 422 | echo "- You are now on branch '$BRANCH'" 423 | echo 424 | } 425 | 426 | cmd_diff() { 427 | parse_args "$@" 428 | 429 | if [ "$NAME" != "" ]; then 430 | expand_nameprefix_arg 431 | BASE=$(git merge-base "$DEVELOP_BRANCH" "$BRANCH") 432 | git diff "$BASE..$BRANCH" 433 | else 434 | if ! git_current_branch | grep -q "^$PREFIX"; then 435 | die "Not on a feature branch. Name one explicitly." 436 | fi 437 | 438 | BASE=$(git merge-base "$DEVELOP_BRANCH" HEAD) 439 | git diff "$BASE" 440 | fi 441 | } 442 | 443 | cmd_checkout() { 444 | parse_args "$@" 445 | 446 | if [ "$NAME" != "" ]; then 447 | expand_nameprefix_arg 448 | git_do checkout "$BRANCH" 449 | else 450 | die "Name a feature branch explicitly." 451 | fi 452 | } 453 | 454 | cmd_co() { 455 | # Alias for checkout 456 | cmd_checkout "$@" 457 | } 458 | 459 | cmd_rebase() { 460 | DEFINE_boolean interactive false 'do an interactive rebase' i 461 | parse_args "$@" 462 | expand_nameprefix_arg_or_current 463 | warn "Will try to rebase '$NAME'..." 464 | require_clean_working_tree 465 | require_branch "$BRANCH" 466 | 467 | git_do checkout -q "$BRANCH" 468 | local OPTS= 469 | if flag interactive; then 470 | OPTS="$OPTS -i" 471 | fi 472 | git_do rebase $OPTS "$DEVELOP_BRANCH" 473 | } 474 | 475 | avoid_accidental_cross_branch_action() { 476 | local current_branch=$(git_current_branch) 477 | if [ "$BRANCH" != "$current_branch" ]; then 478 | warn "Trying to pull from '$BRANCH' while currently on branch '$current_branch'." 479 | warn "To avoid unintended merges, git-flow aborted." 480 | return 1 481 | fi 482 | return 0 483 | } 484 | 485 | cmd_pull() { 486 | #DEFINE_string prefix false 'alternative remote feature branch name prefix' p 487 | DEFINE_boolean rebase false "pull with rebase" r 488 | parse_remote_name "$@" 489 | 490 | if [ -z "$REMOTE" ]; then 491 | die "Name a remote explicitly." 492 | fi 493 | name_or_current 494 | 495 | # To avoid accidentally merging different feature branches into each other, 496 | # die if the current feature branch differs from the requested $NAME 497 | # argument. 498 | local current_branch=$(git_current_branch) 499 | if startswith "$current_branch" "$PREFIX"; then 500 | # we are on a local feature branch already, so $BRANCH must be equal to 501 | # the current branch 502 | avoid_accidental_cross_branch_action || die 503 | fi 504 | 505 | require_clean_working_tree 506 | 507 | if git_branch_exists "$BRANCH"; then 508 | # Again, avoid accidental merges 509 | avoid_accidental_cross_branch_action || die 510 | 511 | # we already have a local branch called like this, so simply pull the 512 | # remote changes in 513 | if flag rebase; then 514 | if ! git_do pull --rebase -q "$REMOTE" "$BRANCH"; then 515 | warn "Pull was aborted. There might be conflicts during rebase or '$REMOTE' might be inaccessible." 516 | exit 1 517 | fi 518 | else 519 | git_do pull -q "$REMOTE" "$BRANCH" || die "Failed to pull from remote '$REMOTE'." 520 | fi 521 | 522 | echo "Pulled $REMOTE's changes into $BRANCH." 523 | else 524 | # setup the local branch clone for the first time 525 | git_do fetch -q "$REMOTE" "$BRANCH" || die "Fetch failed." # stores in FETCH_HEAD 526 | git_do branch --no-track "$BRANCH" FETCH_HEAD || die "Branch failed." 527 | git_do checkout -q "$BRANCH" || die "Checking out new local branch failed." 528 | echo "Created local branch $BRANCH based on $REMOTE's $BRANCH." 529 | fi 530 | } 531 | -------------------------------------------------------------------------------- /git-flow-hotfix: -------------------------------------------------------------------------------- 1 | # 2 | # git-flow -- A collection of Git extensions to provide high-level 3 | # repository operations for Vincent Driessen's branching model. 4 | # 5 | # Original blog post presenting this model is found at: 6 | # http://nvie.com/git-model 7 | # 8 | # Feel free to contribute to this project at: 9 | # http://github.com/nvie/gitflow 10 | # 11 | # Copyright 2010 Vincent Driessen. All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or without 14 | # modification, are permitted provided that the following conditions are met: 15 | # 16 | # 1. Redistributions of source code must retain the above copyright notice, 17 | # this list of conditions and the following disclaimer. 18 | # 19 | # 2. Redistributions in binary form must reproduce the above copyright 20 | # notice, this list of conditions and the following disclaimer in the 21 | # documentation and/or other materials provided with the distribution. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 24 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 26 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 30 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 32 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | # 34 | # The views and conclusions contained in the software and documentation are 35 | # those of the authors and should not be interpreted as representing official 36 | # policies, either expressed or implied, of Vincent Driessen. 37 | # 38 | 39 | init() { 40 | require_git_repo 41 | require_gitflow_initialized 42 | gitflow_load_settings 43 | VERSION_PREFIX=$(eval "echo `git config --get gitflow.prefix.versiontag`") 44 | PREFIX=$(git config --get gitflow.prefix.hotfix) 45 | } 46 | 47 | usage() { 48 | echo "usage: git flow hotfix [list] [-v]" 49 | echo " git flow hotfix start [-F] []" 50 | echo " git flow hotfix finish [-Fsumpk] " 51 | echo " git flow hotfix publish " 52 | echo " git flow hotfix track " 53 | } 54 | 55 | cmd_default() { 56 | cmd_list "$@" 57 | } 58 | 59 | cmd_list() { 60 | DEFINE_boolean verbose false 'verbose (more) output' v 61 | parse_args "$@" 62 | 63 | local hotfix_branches 64 | local current_branch 65 | local short_names 66 | hotfix_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX") 67 | if [ -z "$hotfix_branches" ]; then 68 | warn "No hotfix branches exist." 69 | warn "" 70 | warn "You can start a new hotfix branch:" 71 | warn "" 72 | warn " git flow hotfix start []" 73 | warn "" 74 | exit 0 75 | fi 76 | current_branch=$(git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g') 77 | short_names=$(echo "$hotfix_branches" | sed "s ^$PREFIX g") 78 | 79 | # determine column width first 80 | local width=0 81 | local branch 82 | for branch in $short_names; do 83 | local len=${#branch} 84 | width=$(max $width $len) 85 | done 86 | width=$(($width+3)) 87 | 88 | local branch 89 | for branch in $short_names; do 90 | local fullname=$PREFIX$branch 91 | local base=$(git merge-base "$fullname" "$MASTER_BRANCH") 92 | local master_sha=$(git rev-parse "$MASTER_BRANCH") 93 | local branch_sha=$(git rev-parse "$fullname") 94 | if [ "$fullname" = "$current_branch" ]; then 95 | printf "* " 96 | else 97 | printf " " 98 | fi 99 | if flag verbose; then 100 | printf "%-${width}s" "$branch" 101 | if [ "$branch_sha" = "$master_sha" ]; then 102 | printf "(no commits yet)" 103 | else 104 | local tagname=$(git name-rev --tags --no-undefined --name-only "$base") 105 | local nicename 106 | if [ "$tagname" != "" ]; then 107 | nicename=$tagname 108 | else 109 | nicename=$(git rev-parse --short "$base") 110 | fi 111 | printf "(based on $nicename)" 112 | fi 113 | else 114 | printf "%s" "$branch" 115 | fi 116 | echo 117 | done 118 | } 119 | 120 | cmd_help() { 121 | usage 122 | exit 0 123 | } 124 | 125 | parse_args() { 126 | # parse options 127 | FLAGS "$@" || exit $? 128 | eval set -- "${FLAGS_ARGV}" 129 | 130 | # read arguments into global variables 131 | VERSION=$1 132 | BRANCH=$PREFIX$VERSION 133 | } 134 | 135 | require_version_arg() { 136 | if [ "$VERSION" = "" ]; then 137 | warn "Missing argument " 138 | usage 139 | exit 1 140 | fi 141 | } 142 | 143 | require_base_is_on_master() { 144 | if ! git branch --no-color --contains "$BASE" 2>/dev/null \ 145 | | sed 's/[* ] //g' \ 146 | | grep -q "^$MASTER_BRANCH\$"; then 147 | die "fatal: Given base '$BASE' is not a valid commit on '$MASTER_BRANCH'." 148 | fi 149 | } 150 | 151 | require_no_existing_hotfix_branches() { 152 | local hotfix_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX") 153 | local first_branch=$(echo ${hotfix_branches} | head -n1) 154 | first_branch=${first_branch#$PREFIX} 155 | [ -z "$hotfix_branches" ] || \ 156 | die "There is an existing hotfix branch ($first_branch). Finish that one first." 157 | } 158 | 159 | cmd_start() { 160 | DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F 161 | parse_args "$@" 162 | BASE=${2:-$MASTER_BRANCH} 163 | require_version_arg 164 | require_base_is_on_master 165 | require_no_existing_hotfix_branches 166 | 167 | # sanity checks 168 | require_clean_working_tree 169 | require_branch_absent "$BRANCH" 170 | require_tag_absent "$VERSION_PREFIX$VERSION" 171 | if flag fetch; then 172 | git_do fetch -q "$ORIGIN" "$MASTER_BRANCH" 173 | fi 174 | if has "$ORIGIN/$MASTER_BRANCH" $(git_remote_branches); then 175 | require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH" 176 | fi 177 | 178 | # create branch 179 | git_do checkout -b "$BRANCH" "$BASE" 180 | 181 | echo 182 | echo "Summary of actions:" 183 | echo "- A new branch '$BRANCH' was created, based on '$BASE'" 184 | echo "- You are now on branch '$BRANCH'" 185 | echo 186 | echo "Follow-up actions:" 187 | echo "- Bump the version number now!" 188 | echo "- Start committing your hot fixes" 189 | echo "- When done, run:" 190 | echo 191 | echo " git flow hotfix finish '$VERSION'" 192 | echo 193 | } 194 | 195 | cmd_publish() { 196 | parse_args "$@" 197 | require_version_arg 198 | 199 | # sanity checks 200 | require_clean_working_tree 201 | require_branch "$BRANCH" 202 | git_do fetch -q "$ORIGIN" 203 | require_branch_absent "$ORIGIN/$BRANCH" 204 | 205 | # create remote branch 206 | git_do push "$ORIGIN" "$BRANCH:refs/heads/$BRANCH" 207 | git_do fetch -q "$ORIGIN" 208 | 209 | # configure remote tracking 210 | git config "branch.$BRANCH.remote" "$ORIGIN" 211 | git config "branch.$BRANCH.merge" "refs/heads/$BRANCH" 212 | git_do checkout "$BRANCH" 213 | 214 | echo 215 | echo "Summary of actions:" 216 | echo "- A new remote branch '$BRANCH' was created" 217 | echo "- The local branch '$BRANCH' was configured to track the remote branch" 218 | echo "- You are now on branch '$BRANCH'" 219 | echo 220 | } 221 | 222 | cmd_track() { 223 | parse_args "$@" 224 | require_version_arg 225 | 226 | # sanity checks 227 | require_clean_working_tree 228 | require_branch_absent "$BRANCH" 229 | git_do fetch -q "$ORIGIN" 230 | require_branch "$ORIGIN/$BRANCH" 231 | 232 | # create tracking branch 233 | git_do checkout -b "$BRANCH" "$ORIGIN/$BRANCH" 234 | 235 | echo 236 | echo "Summary of actions:" 237 | echo "- A new remote tracking branch '$BRANCH' was created" 238 | echo "- You are now on branch '$BRANCH'" 239 | echo 240 | } 241 | 242 | cmd_finish() { 243 | DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F 244 | DEFINE_boolean sign false "sign the release tag cryptographically" s 245 | DEFINE_string signingkey "" "use the given GPG-key for the digital signature (implies -s)" u 246 | DEFINE_string message "" "use the given tag message" m 247 | DEFINE_string messagefile "" "use the contents of the given file as tag message" f 248 | DEFINE_boolean push false "push to $ORIGIN after performing finish" p 249 | DEFINE_boolean keep false "keep branch after performing finish" k 250 | DEFINE_boolean notag false "don't tag this release" n 251 | parse_args "$@" 252 | require_version_arg 253 | 254 | # handle flags that imply other flags 255 | if [ "$FLAGS_signingkey" != "" ]; then 256 | FLAGS_sign=$FLAGS_TRUE 257 | fi 258 | 259 | # sanity checks 260 | require_branch "$BRANCH" 261 | require_clean_working_tree 262 | if flag fetch; then 263 | git_do fetch -q "$ORIGIN" "$MASTER_BRANCH" || \ 264 | die "Could not fetch $MASTER_BRANCH from $ORIGIN." 265 | git_do fetch -q "$ORIGIN" "$DEVELOP_BRANCH" || \ 266 | die "Could not fetch $DEVELOP_BRANCH from $ORIGIN." 267 | fi 268 | if has "$ORIGIN/$MASTER_BRANCH" $(git_remote_branches); then 269 | require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH" 270 | fi 271 | if has "$ORIGIN/$DEVELOP_BRANCH" $(git_remote_branches); then 272 | require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH" 273 | fi 274 | 275 | # try to merge into master 276 | # in case a previous attempt to finish this release branch has failed, 277 | # but the merge into master was successful, we skip it now 278 | if ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then 279 | git_do checkout "$MASTER_BRANCH" || \ 280 | die "Could not check out $MASTER_BRANCH." 281 | git_do merge --no-ff "$BRANCH" || \ 282 | die "There were merge conflicts." 283 | # TODO: What do we do now? 284 | fi 285 | 286 | if noflag notag; then 287 | # try to tag the release 288 | # in case a previous attempt to finish this release branch has failed, 289 | # but the tag was set successful, we skip it now 290 | local tagname=$VERSION_PREFIX$VERSION 291 | if ! git_tag_exists "$tagname"; then 292 | local opts="-a" 293 | flag sign && opts="$opts -s" 294 | [ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'" 295 | [ "$FLAGS_message" != "" ] && opts="$opts -m '$FLAGS_message'" 296 | [ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'" 297 | eval git_do tag $opts "$VERSION_PREFIX$VERSION" "$BRANCH" || \ 298 | die "Tagging failed. Please run finish again to retry." 299 | fi 300 | fi 301 | 302 | # try to merge into develop 303 | # in case a previous attempt to finish this release branch has failed, 304 | # but the merge into develop was successful, we skip it now 305 | if ! git_is_branch_merged_into "$BRANCH" "$DEVELOP_BRANCH"; then 306 | git_do checkout "$DEVELOP_BRANCH" || \ 307 | die "Could not check out $DEVELOP_BRANCH." 308 | 309 | # TODO: Actually, accounting for 'git describe' pays, so we should 310 | # ideally git merge --no-ff $tagname here, instead! 311 | git_do merge --no-ff "$BRANCH" || \ 312 | die "There were merge conflicts." 313 | # TODO: What do we do now? 314 | fi 315 | 316 | # delete branch 317 | if noflag keep; then 318 | git_do branch -d "$BRANCH" 319 | fi 320 | 321 | if flag push; then 322 | git_do push "$ORIGIN" "$DEVELOP_BRANCH" || \ 323 | die "Could not push to $DEVELOP_BRANCH from $ORIGIN." 324 | git_do push "$ORIGIN" "$MASTER_BRANCH" || \ 325 | die "Could not push to $MASTER_BRANCH from $ORIGIN." 326 | if noflag notag; then 327 | git_do push --tags "$ORIGIN" || \ 328 | die "Could not push tags to $ORIGIN." 329 | fi 330 | fi 331 | 332 | echo 333 | echo "Summary of actions:" 334 | echo "- Latest objects have been fetched from '$ORIGIN'" 335 | echo "- Hotfix branch has been merged into '$MASTER_BRANCH'" 336 | if noflag notag; then 337 | echo "- The hotfix was tagged '$VERSION_PREFIX$VERSION'" 338 | fi 339 | echo "- Hotfix branch has been back-merged into '$DEVELOP_BRANCH'" 340 | if flag keep; then 341 | echo "- Hotfix branch '$BRANCH' is still available" 342 | else 343 | echo "- Hotfix branch '$BRANCH' has been deleted" 344 | fi 345 | if flag push; then 346 | echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'" 347 | fi 348 | echo 349 | } 350 | -------------------------------------------------------------------------------- /git-flow-init: -------------------------------------------------------------------------------- 1 | # 2 | # git-flow -- A collection of Git extensions to provide high-level 3 | # repository operations for Vincent Driessen's branching model. 4 | # 5 | # Original blog post presenting this model is found at: 6 | # http://nvie.com/git-model 7 | # 8 | # Feel free to contribute to this project at: 9 | # http://github.com/nvie/gitflow 10 | # 11 | # Copyright 2010 Vincent Driessen. All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or without 14 | # modification, are permitted provided that the following conditions are met: 15 | # 16 | # 1. Redistributions of source code must retain the above copyright notice, 17 | # this list of conditions and the following disclaimer. 18 | # 19 | # 2. Redistributions in binary form must reproduce the above copyright 20 | # notice, this list of conditions and the following disclaimer in the 21 | # documentation and/or other materials provided with the distribution. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 24 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 26 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 30 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 32 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | # 34 | # The views and conclusions contained in the software and documentation are 35 | # those of the authors and should not be interpreted as representing official 36 | # policies, either expressed or implied, of Vincent Driessen. 37 | # 38 | 39 | usage() { 40 | echo "usage: git flow init [-fd]" 41 | } 42 | 43 | parse_args() { 44 | # parse options 45 | FLAGS "$@" || exit $? 46 | eval set -- "${FLAGS_ARGV}" 47 | } 48 | 49 | # Default entry when no SUBACTION is given 50 | cmd_default() { 51 | DEFINE_boolean force false 'force setting of gitflow branches, even if already configured' f 52 | DEFINE_boolean defaults false 'use default branch naming conventions' d 53 | parse_args "$@" 54 | 55 | if ! git rev-parse --git-dir >/dev/null 2>&1; then 56 | git_do init 57 | else 58 | # assure that we are not working in a repo with local changes 59 | git_repo_is_headless || require_clean_working_tree 60 | fi 61 | 62 | # running git flow init on an already initialized repo is fine 63 | if gitflow_is_initialized && ! flag force; then 64 | warn "Already initialized for gitflow." 65 | warn "To force reinitialization, use: git flow init -f" 66 | exit 0 67 | fi 68 | 69 | local branch_count 70 | local answer 71 | 72 | if flag defaults; then 73 | warn "Using default branch names." 74 | fi 75 | 76 | # add a master branch if no such branch exists yet 77 | local master_branch 78 | if gitflow_has_master_configured && ! flag force; then 79 | master_branch=$(git config --get gitflow.branch.master) 80 | else 81 | # Two cases are distinguished: 82 | # 1. A fresh git repo (without any branches) 83 | # We will create a new master/develop branch for the user 84 | # 2. Some branches do already exist 85 | # We will disallow creation of new master/develop branches and 86 | # rather allow to use existing branches for git-flow. 87 | local default_suggestion 88 | local should_check_existence 89 | branch_count=$(git_local_branches | wc -l) 90 | if [ "$branch_count" -eq 0 ]; then 91 | echo "No branches exist yet. Base branches must be created now." 92 | should_check_existence=NO 93 | default_suggestion=$(git config --get gitflow.branch.master || echo master) 94 | else 95 | echo 96 | echo "Which branch should be used for bringing forth production releases?" 97 | git_local_branches | sed 's/^.*$/ - &/g' 98 | 99 | should_check_existence=YES 100 | default_suggestion= 101 | for guess in $(git config --get gitflow.branch.master) \ 102 | 'production' 'main' 'master'; do 103 | if git_local_branch_exists "$guess"; then 104 | default_suggestion="$guess" 105 | break 106 | fi 107 | done 108 | fi 109 | 110 | printf "Branch name for production releases: [$default_suggestion] " 111 | if noflag defaults; then 112 | read answer 113 | else 114 | printf "\n" 115 | fi 116 | master_branch=${answer:-$default_suggestion} 117 | 118 | # check existence in case of an already existing repo 119 | if [ "$should_check_existence" = "YES" ]; then 120 | # if no local branch exists and a remote branch of the same 121 | # name exists, checkout that branch and use it for master 122 | if ! git_local_branch_exists "$master_branch" && \ 123 | git_remote_branch_exists "origin/$master_branch"; then 124 | git_do branch "$master_branch" "origin/$master_branch" >/dev/null 2>&1 125 | elif ! git_local_branch_exists "$master_branch"; then 126 | die "Local branch '$master_branch' does not exist." 127 | fi 128 | fi 129 | 130 | # store the name of the master branch 131 | git_do config gitflow.branch.master "$master_branch" 132 | fi 133 | 134 | # add a develop branch if no such branch exists yet 135 | local develop_branch 136 | if gitflow_has_develop_configured && ! flag force; then 137 | develop_branch=$(git config --get gitflow.branch.develop) 138 | else 139 | # Again, the same two cases as with the master selection are 140 | # considered (fresh repo or repo that contains branches) 141 | local default_suggestion 142 | local should_check_existence 143 | branch_count=$(git_local_branches | grep -v "^${master_branch}\$" | wc -l) 144 | if [ "$branch_count" -eq 0 ]; then 145 | should_check_existence=NO 146 | default_suggestion=$(git config --get gitflow.branch.develop || echo develop) 147 | else 148 | echo 149 | echo "Which branch should be used for integration of the \"next release\"?" 150 | git_local_branches | grep -v "^${master_branch}\$" | sed 's/^.*$/ - &/g' 151 | 152 | should_check_existence=YES 153 | default_suggestion= 154 | for guess in $(git config --get gitflow.branch.develop) \ 155 | 'develop' 'int' 'integration' 'master'; do 156 | if git_local_branch_exists "$guess" && [ "$guess" != "$master_branch" ]; then 157 | default_suggestion="$guess" 158 | break 159 | fi 160 | done 161 | 162 | if [ -z $default_suggestion ]; then 163 | should_check_existence=NO 164 | default_suggestion=$(git config --get gitflow.branch.develop || echo develop) 165 | fi 166 | 167 | fi 168 | 169 | printf "Branch name for \"next release\" development: [$default_suggestion] " 170 | if noflag defaults; then 171 | read answer 172 | else 173 | printf "\n" 174 | fi 175 | develop_branch=${answer:-$default_suggestion} 176 | 177 | if [ "$master_branch" = "$develop_branch" ]; then 178 | die "Production and integration branches should differ." 179 | fi 180 | 181 | # check existence in case of an already existing repo 182 | if [ "$should_check_existence" = "YES" ]; then 183 | git_local_branch_exists "$develop_branch" || \ 184 | die "Local branch '$develop_branch' does not exist." 185 | fi 186 | 187 | # store the name of the develop branch 188 | git_do config gitflow.branch.develop "$develop_branch" 189 | fi 190 | 191 | # Creation of HEAD 192 | # ---------------- 193 | # We create a HEAD now, if it does not exist yet (in a fresh repo). We need 194 | # it to be able to create new branches. 195 | local created_gitflow_branch=0 196 | if ! git rev-parse --quiet --verify HEAD >/dev/null 2>&1; then 197 | git_do symbolic-ref HEAD "refs/heads/$master_branch" 198 | git_do commit --allow-empty --quiet -m "Initial commit" 199 | created_gitflow_branch=1 200 | fi 201 | 202 | # Creation of master 203 | # ------------------ 204 | # At this point, there always is a master branch: either it existed already 205 | # (and was picked interactively as the production branch) or it has just 206 | # been created in a fresh repo 207 | 208 | # Creation of develop 209 | # ------------------- 210 | # The develop branch possibly does not exist yet. This is the case when, 211 | # in a git init'ed repo with one or more commits, master was picked as the 212 | # default production branch and develop was "created". We should create 213 | # the develop branch now in that case (we base it on master, of course) 214 | if ! git_local_branch_exists "$develop_branch"; then 215 | if git_remote_branch_exists "origin/$develop_branch"; then 216 | git_do branch "$develop_branch" "origin/$develop_branch" >/dev/null 2>&1 217 | else 218 | git_do branch --no-track "$develop_branch" "$master_branch" 219 | fi 220 | created_gitflow_branch=1 221 | fi 222 | 223 | # assert the gitflow repo has been correctly initialized 224 | gitflow_is_initialized 225 | 226 | # switch to develop branch if its newly created 227 | if [ $created_gitflow_branch -eq 1 ]; then 228 | git_do checkout -q "$develop_branch" 229 | fi 230 | 231 | # finally, ask the user for naming conventions (branch and tag prefixes) 232 | if flag force || \ 233 | ! git config --get gitflow.prefix.feature >/dev/null 2>&1 || 234 | ! git config --get gitflow.prefix.release >/dev/null 2>&1 || 235 | ! git config --get gitflow.prefix.hotfix >/dev/null 2>&1 || 236 | ! git config --get gitflow.prefix.support >/dev/null 2>&1 || 237 | ! git config --get gitflow.prefix.versiontag >/dev/null 2>&1; then 238 | echo 239 | echo "How to name your supporting branch prefixes?" 240 | fi 241 | 242 | local prefix 243 | 244 | # Feature branches 245 | if ! git config --get gitflow.prefix.feature >/dev/null 2>&1 || flag force; then 246 | default_suggestion=$(git config --get gitflow.prefix.feature || echo feature/) 247 | printf "Feature branches? [$default_suggestion] " 248 | if noflag defaults; then 249 | read answer 250 | else 251 | printf "\n" 252 | fi 253 | [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} 254 | git_do config gitflow.prefix.feature "$prefix" 255 | fi 256 | 257 | # Release branches 258 | if ! git config --get gitflow.prefix.release >/dev/null 2>&1 || flag force; then 259 | default_suggestion=$(git config --get gitflow.prefix.release || echo release/) 260 | printf "Release branches? [$default_suggestion] " 261 | if noflag defaults; then 262 | read answer 263 | else 264 | printf "\n" 265 | fi 266 | [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} 267 | git_do config gitflow.prefix.release "$prefix" 268 | fi 269 | 270 | 271 | # Hotfix branches 272 | if ! git config --get gitflow.prefix.hotfix >/dev/null 2>&1 || flag force; then 273 | default_suggestion=$(git config --get gitflow.prefix.hotfix || echo hotfix/) 274 | printf "Hotfix branches? [$default_suggestion] " 275 | if noflag defaults; then 276 | read answer 277 | else 278 | printf "\n" 279 | fi 280 | [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} 281 | git_do config gitflow.prefix.hotfix "$prefix" 282 | fi 283 | 284 | 285 | # Support branches 286 | if ! git config --get gitflow.prefix.support >/dev/null 2>&1 || flag force; then 287 | default_suggestion=$(git config --get gitflow.prefix.support || echo support/) 288 | printf "Support branches? [$default_suggestion] " 289 | if noflag defaults; then 290 | read answer 291 | else 292 | printf "\n" 293 | fi 294 | [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} 295 | git_do config gitflow.prefix.support "$prefix" 296 | fi 297 | 298 | 299 | # Version tag prefix 300 | if ! git config --get gitflow.prefix.versiontag >/dev/null 2>&1 || flag force; then 301 | default_suggestion=$(git config --get gitflow.prefix.versiontag || echo "") 302 | printf "Version tag prefix? [$default_suggestion] " 303 | if noflag defaults; then 304 | read answer 305 | else 306 | printf "\n" 307 | fi 308 | [ "$answer" = "-" ] && prefix= || prefix=${answer:-$default_suggestion} 309 | git_do config gitflow.prefix.versiontag "$prefix" 310 | fi 311 | 312 | 313 | # TODO: what to do with origin? 314 | } 315 | 316 | cmd_help() { 317 | usage 318 | exit 0 319 | } 320 | -------------------------------------------------------------------------------- /git-flow-release: -------------------------------------------------------------------------------- 1 | # 2 | # git-flow -- A collection of Git extensions to provide high-level 3 | # repository operations for Vincent Driessen's branching model. 4 | # 5 | # Original blog post presenting this model is found at: 6 | # http://nvie.com/git-model 7 | # 8 | # Feel free to contribute to this project at: 9 | # http://github.com/nvie/gitflow 10 | # 11 | # Copyright 2010 Vincent Driessen. All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or without 14 | # modification, are permitted provided that the following conditions are met: 15 | # 16 | # 1. Redistributions of source code must retain the above copyright notice, 17 | # this list of conditions and the following disclaimer. 18 | # 19 | # 2. Redistributions in binary form must reproduce the above copyright 20 | # notice, this list of conditions and the following disclaimer in the 21 | # documentation and/or other materials provided with the distribution. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 24 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 26 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 30 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 32 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | # 34 | # The views and conclusions contained in the software and documentation are 35 | # those of the authors and should not be interpreted as representing official 36 | # policies, either expressed or implied, of Vincent Driessen. 37 | # 38 | 39 | init() { 40 | require_git_repo 41 | require_gitflow_initialized 42 | gitflow_load_settings 43 | VERSION_PREFIX=$(eval "echo `git config --get gitflow.prefix.versiontag`") 44 | PREFIX=$(git config --get gitflow.prefix.release) 45 | } 46 | 47 | usage() { 48 | echo "usage: git flow release [list] [-v]" 49 | echo " git flow release start [-F] []" 50 | echo " git flow release finish [-FsumpkS] " 51 | echo " git flow release publish " 52 | echo " git flow release track " 53 | } 54 | 55 | cmd_default() { 56 | cmd_list "$@" 57 | } 58 | 59 | cmd_list() { 60 | DEFINE_boolean verbose false 'verbose (more) output' v 61 | parse_args "$@" 62 | 63 | local release_branches 64 | local current_branch 65 | local short_names 66 | release_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX") 67 | if [ -z "$release_branches" ]; then 68 | warn "No release branches exist." 69 | warn "" 70 | warn "You can start a new release branch:" 71 | warn "" 72 | warn " git flow release start []" 73 | warn "" 74 | exit 0 75 | fi 76 | 77 | current_branch=$(git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g') 78 | short_names=$(echo "$release_branches" | sed "s ^$PREFIX g") 79 | 80 | # determine column width first 81 | local width=0 82 | local branch 83 | for branch in $short_names; do 84 | local len=${#branch} 85 | width=$(max $width $len) 86 | done 87 | width=$(($width+3)) 88 | 89 | local branch 90 | for branch in $short_names; do 91 | local fullname=$PREFIX$branch 92 | local base=$(git merge-base "$fullname" "$DEVELOP_BRANCH") 93 | local develop_sha=$(git rev-parse "$DEVELOP_BRANCH") 94 | local branch_sha=$(git rev-parse "$fullname") 95 | if [ "$fullname" = "$current_branch" ]; then 96 | printf "* " 97 | else 98 | printf " " 99 | fi 100 | if flag verbose; then 101 | printf "%-${width}s" "$branch" 102 | if [ "$branch_sha" = "$develop_sha" ]; then 103 | printf "(no commits yet)" 104 | else 105 | local nicename=$(git rev-parse --short "$base") 106 | printf "(based on $nicename)" 107 | fi 108 | else 109 | printf "%s" "$branch" 110 | fi 111 | echo 112 | done 113 | } 114 | 115 | cmd_help() { 116 | usage 117 | exit 0 118 | } 119 | 120 | parse_args() { 121 | # parse options 122 | FLAGS "$@" || exit $? 123 | eval set -- "${FLAGS_ARGV}" 124 | 125 | # read arguments into global variables 126 | VERSION=$1 127 | BRANCH=$PREFIX$VERSION 128 | } 129 | 130 | require_version_arg() { 131 | if [ "$VERSION" = "" ]; then 132 | warn "Missing argument " 133 | usage 134 | exit 1 135 | fi 136 | } 137 | 138 | require_base_is_on_develop() { 139 | if ! git_do branch --no-color --contains "$BASE" 2>/dev/null \ 140 | | sed 's/[* ] //g' \ 141 | | grep -q "^$DEVELOP_BRANCH\$"; then 142 | die "fatal: Given base '$BASE' is not a valid commit on '$DEVELOP_BRANCH'." 143 | fi 144 | } 145 | 146 | require_no_existing_release_branches() { 147 | local release_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX") 148 | local first_branch=$(echo ${release_branches} | head -n1) 149 | first_branch=${first_branch#$PREFIX} 150 | [ -z "$release_branches" ] || \ 151 | die "There is an existing release branch ($first_branch). Finish that one first." 152 | } 153 | 154 | cmd_start() { 155 | DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F 156 | parse_args "$@" 157 | BASE=${2:-$DEVELOP_BRANCH} 158 | require_version_arg 159 | require_base_is_on_develop 160 | require_no_existing_release_branches 161 | 162 | # sanity checks 163 | require_clean_working_tree 164 | require_branch_absent "$BRANCH" 165 | require_tag_absent "$VERSION_PREFIX$VERSION" 166 | if flag fetch; then 167 | git_do fetch -q "$ORIGIN" "$DEVELOP_BRANCH" 168 | fi 169 | if has "$ORIGIN/$DEVELOP_BRANCH" $(git_remote_branches); then 170 | require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH" 171 | fi 172 | 173 | # create branch 174 | git_do checkout -b "$BRANCH" "$BASE" 175 | 176 | echo 177 | echo "Summary of actions:" 178 | echo "- A new branch '$BRANCH' was created, based on '$BASE'" 179 | echo "- You are now on branch '$BRANCH'" 180 | echo 181 | echo "Follow-up actions:" 182 | echo "- Bump the version number now!" 183 | echo "- Start committing last-minute fixes in preparing your release" 184 | echo "- When done, run:" 185 | echo 186 | echo " git flow release finish '$VERSION'" 187 | echo 188 | } 189 | 190 | cmd_finish() { 191 | DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F 192 | DEFINE_boolean sign false "sign the release tag cryptographically" s 193 | DEFINE_string signingkey "" "use the given GPG-key for the digital signature (implies -s)" u 194 | DEFINE_string message "" "use the given tag message" m 195 | DEFINE_string messagefile "" "use the contents of the given file as a tag message" f 196 | DEFINE_boolean push false "push to $ORIGIN after performing finish" p 197 | DEFINE_boolean keep false "keep branch after performing finish" k 198 | DEFINE_boolean notag false "don't tag this release" n 199 | DEFINE_boolean squash false "squash release during merge" S 200 | 201 | parse_args "$@" 202 | require_version_arg 203 | 204 | # handle flags that imply other flags 205 | if [ "$FLAGS_signingkey" != "" ]; then 206 | FLAGS_sign=$FLAGS_TRUE 207 | fi 208 | 209 | # sanity checks 210 | require_branch "$BRANCH" 211 | require_clean_working_tree 212 | if flag fetch; then 213 | git_do fetch -q "$ORIGIN" "$MASTER_BRANCH" || \ 214 | die "Could not fetch $MASTER_BRANCH from $ORIGIN." 215 | git_do fetch -q "$ORIGIN" "$DEVELOP_BRANCH" || \ 216 | die "Could not fetch $DEVELOP_BRANCH from $ORIGIN." 217 | fi 218 | if has "$ORIGIN/$MASTER_BRANCH" $(git_remote_branches); then 219 | require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH" 220 | fi 221 | if has "$ORIGIN/$DEVELOP_BRANCH" $(git_remote_branches); then 222 | require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH" 223 | fi 224 | 225 | # try to merge into master 226 | # in case a previous attempt to finish this release branch has failed, 227 | # but the merge into master was successful, we skip it now 228 | if ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then 229 | git_do checkout "$MASTER_BRANCH" || \ 230 | die "Could not check out $MASTER_BRANCH." 231 | if noflag squash; then 232 | git_do merge --no-ff "$BRANCH" || \ 233 | die "There were merge conflicts." 234 | # TODO: What do we do now? 235 | else 236 | git_do merge --squash "$BRANCH" || \ 237 | die "There were merge conflicts." 238 | git_do commit 239 | fi 240 | fi 241 | 242 | if noflag notag; then 243 | # try to tag the release 244 | # in case a previous attempt to finish this release branch has failed, 245 | # but the tag was set successful, we skip it now 246 | local tagname=$VERSION_PREFIX$VERSION 247 | if ! git_tag_exists "$tagname"; then 248 | local opts="-a" 249 | flag sign && opts="$opts -s" 250 | [ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'" 251 | [ "$FLAGS_message" != "" ] && opts="$opts -m '$FLAGS_message'" 252 | [ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'" 253 | eval git_do tag $opts "$tagname" "$BRANCH" || \ 254 | die "Tagging failed. Please run finish again to retry." 255 | fi 256 | fi 257 | 258 | # try to merge into develop 259 | # in case a previous attempt to finish this release branch has failed, 260 | # but the merge into develop was successful, we skip it now 261 | if ! git_is_branch_merged_into "$BRANCH" "$DEVELOP_BRANCH"; then 262 | git_do checkout "$DEVELOP_BRANCH" || \ 263 | die "Could not check out $DEVELOP_BRANCH." 264 | 265 | # TODO: Actually, accounting for 'git describe' pays, so we should 266 | # ideally git merge --no-ff $tagname here, instead! 267 | if noflag squash; then 268 | git_do merge --no-ff "$BRANCH" || \ 269 | die "There were merge conflicts." 270 | # TODO: What do we do now? 271 | else 272 | git_do merge --squash "$BRANCH" || \ 273 | die "There were merge conflicts." 274 | # TODO: What do we do now? 275 | git_do commit 276 | fi 277 | fi 278 | 279 | # delete branch 280 | if noflag keep; then 281 | if [ "$BRANCH" = "$(git_current_branch)" ]; then 282 | git_do checkout "$MASTER_BRANCH" 283 | fi 284 | git_do branch -d "$BRANCH" 285 | fi 286 | 287 | if flag push; then 288 | git_do push "$ORIGIN" "$DEVELOP_BRANCH" || \ 289 | die "Could not push to $DEVELOP_BRANCH from $ORIGIN." 290 | git_do push "$ORIGIN" "$MASTER_BRANCH" || \ 291 | die "Could not push to $MASTER_BRANCH from $ORIGIN." 292 | if noflag notag; then 293 | git_do push --tags "$ORIGIN" || \ 294 | die "Could not push tags to $ORIGIN." 295 | fi 296 | git_do push "$ORIGIN" :"$BRANCH" || \ 297 | die "Could not delete the remote $BRANCH in $ORIGIN." 298 | fi 299 | 300 | echo 301 | echo "Summary of actions:" 302 | echo "- Latest objects have been fetched from '$ORIGIN'" 303 | echo "- Release branch has been merged into '$MASTER_BRANCH'" 304 | if noflag notag; then 305 | echo "- The release was tagged '$tagname'" 306 | fi 307 | echo "- Release branch has been back-merged into '$DEVELOP_BRANCH'" 308 | if flag keep; then 309 | echo "- Release branch '$BRANCH' is still available" 310 | else 311 | echo "- Release branch '$BRANCH' has been deleted" 312 | fi 313 | if flag push; then 314 | echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'" 315 | echo "- Release branch '$BRANCH' in '$ORIGIN' has been deleted." 316 | fi 317 | echo 318 | } 319 | 320 | cmd_publish() { 321 | parse_args "$@" 322 | require_version_arg 323 | 324 | # sanity checks 325 | require_clean_working_tree 326 | require_branch "$BRANCH" 327 | git_do fetch -q "$ORIGIN" 328 | require_branch_absent "$ORIGIN/$BRANCH" 329 | 330 | # create remote branch 331 | git_do push "$ORIGIN" "$BRANCH:refs/heads/$BRANCH" 332 | git_do fetch -q "$ORIGIN" 333 | 334 | # configure remote tracking 335 | git_do config "branch.$BRANCH.remote" "$ORIGIN" 336 | git_do config "branch.$BRANCH.merge" "refs/heads/$BRANCH" 337 | git_do checkout "$BRANCH" 338 | 339 | echo 340 | echo "Summary of actions:" 341 | echo "- A new remote branch '$BRANCH' was created" 342 | echo "- The local branch '$BRANCH' was configured to track the remote branch" 343 | echo "- You are now on branch '$BRANCH'" 344 | echo 345 | } 346 | 347 | cmd_track() { 348 | parse_args "$@" 349 | require_version_arg 350 | 351 | # sanity checks 352 | require_clean_working_tree 353 | require_branch_absent "$BRANCH" 354 | git_do fetch -q "$ORIGIN" 355 | require_branch "$ORIGIN/$BRANCH" 356 | 357 | # create tracking branch 358 | git_do checkout -b "$BRANCH" "$ORIGIN/$BRANCH" 359 | 360 | echo 361 | echo "Summary of actions:" 362 | echo "- A new remote tracking branch '$BRANCH' was created" 363 | echo "- You are now on branch '$BRANCH'" 364 | echo 365 | } 366 | -------------------------------------------------------------------------------- /git-flow-support: -------------------------------------------------------------------------------- 1 | # 2 | # git-flow -- A collection of Git extensions to provide high-level 3 | # repository operations for Vincent Driessen's branching model. 4 | # 5 | # Original blog post presenting this model is found at: 6 | # http://nvie.com/git-model 7 | # 8 | # Feel free to contribute to this project at: 9 | # http://github.com/nvie/gitflow 10 | # 11 | # Copyright 2010 Vincent Driessen. All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or without 14 | # modification, are permitted provided that the following conditions are met: 15 | # 16 | # 1. Redistributions of source code must retain the above copyright notice, 17 | # this list of conditions and the following disclaimer. 18 | # 19 | # 2. Redistributions in binary form must reproduce the above copyright 20 | # notice, this list of conditions and the following disclaimer in the 21 | # documentation and/or other materials provided with the distribution. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 24 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 26 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 30 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 32 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | # 34 | # The views and conclusions contained in the software and documentation are 35 | # those of the authors and should not be interpreted as representing official 36 | # policies, either expressed or implied, of Vincent Driessen. 37 | # 38 | 39 | init() { 40 | require_git_repo 41 | require_gitflow_initialized 42 | gitflow_load_settings 43 | VERSION_PREFIX=$(eval "echo `git config --get gitflow.prefix.versiontag`") 44 | PREFIX=$(git config --get gitflow.prefix.support) 45 | } 46 | 47 | warn "note: The support subcommand is still very EXPERIMENTAL!" 48 | warn "note: DO NOT use it in a production situation." 49 | 50 | usage() { 51 | echo "usage: git flow support [list] [-v]" 52 | echo " git flow support start [-F] " 53 | } 54 | 55 | cmd_default() { 56 | cmd_list "$@" 57 | } 58 | 59 | cmd_list() { 60 | DEFINE_boolean verbose false 'verbose (more) output' v 61 | parse_args "$@" 62 | 63 | local support_branches 64 | local current_branch 65 | local short_names 66 | support_branches=$(echo "$(git_local_branches)" | grep "^$PREFIX") 67 | if [ -z "$support_branches" ]; then 68 | warn "No support branches exist." 69 | warn "" 70 | warn "You can start a new support branch:" 71 | warn "" 72 | warn " git flow support start " 73 | warn "" 74 | exit 0 75 | fi 76 | current_branch=$(git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g') 77 | short_names=$(echo "$support_branches" | sed "s ^$PREFIX g") 78 | 79 | # determine column width first 80 | local width=0 81 | local branch 82 | for branch in $short_names; do 83 | local len=${#branch} 84 | width=$(max $width $len) 85 | done 86 | width=$(($width+3)) 87 | 88 | local branch 89 | for branch in $short_names; do 90 | local fullname=$PREFIX$branch 91 | local base=$(git merge-base "$fullname" "$MASTER_BRANCH") 92 | local master_sha=$(git rev-parse "$MASTER_BRANCH") 93 | local branch_sha=$(git rev-parse "$fullname") 94 | if [ "$fullname" = "$current_branch" ]; then 95 | printf "* " 96 | else 97 | printf " " 98 | fi 99 | if flag verbose; then 100 | printf "%-${width}s" "$branch" 101 | if [ "$branch_sha" = "$master_sha" ]; then 102 | printf "(no commits yet)" 103 | else 104 | local tagname=$(git name-rev --tags --no-undefined --name-only "$base") 105 | local nicename 106 | if [ "$tagname" != "" ]; then 107 | nicename=$tagname 108 | else 109 | nicename=$(git rev-parse --short "$base") 110 | fi 111 | printf "(based on $nicename)" 112 | fi 113 | else 114 | printf "%s" "$branch" 115 | fi 116 | echo 117 | done 118 | } 119 | 120 | cmd_help() { 121 | usage 122 | exit 0 123 | } 124 | 125 | parse_args() { 126 | # parse options 127 | FLAGS "$@" || exit $? 128 | eval set -- "${FLAGS_ARGV}" 129 | 130 | # read arguments into global variables 131 | VERSION=$1 132 | BASE=$2 133 | BRANCH=$PREFIX$VERSION 134 | } 135 | 136 | require_version_arg() { 137 | if [ "$VERSION" = "" ]; then 138 | warn "Missing argument " 139 | usage 140 | exit 1 141 | fi 142 | } 143 | 144 | require_base_arg() { 145 | if [ "$BASE" = "" ]; then 146 | warn "Missing argument " 147 | usage 148 | exit 1 149 | fi 150 | } 151 | 152 | require_base_is_on_master() { 153 | if ! git branch --no-color --contains "$BASE" 2>/dev/null \ 154 | | sed 's/[* ] //g' \ 155 | | grep -q "^$MASTER_BRANCH\$"; then 156 | die "fatal: Given base '$BASE' is not a valid commit on '$MASTER_BRANCH'." 157 | fi 158 | } 159 | 160 | cmd_start() { 161 | DEFINE_boolean fetch false "fetch from $ORIGIN before performing finish" F 162 | parse_args "$@" 163 | require_version_arg 164 | require_base_arg 165 | require_base_is_on_master 166 | 167 | # sanity checks 168 | require_clean_working_tree 169 | 170 | # fetch remote changes 171 | if flag fetch; then 172 | git_do fetch -q "$ORIGIN" "$BASE" 173 | fi 174 | require_branch_absent "$BRANCH" 175 | 176 | # create branch 177 | git_do checkout -b "$BRANCH" "$BASE" 178 | 179 | echo 180 | echo "Summary of actions:" 181 | echo "- A new branch '$BRANCH' was created, based on '$BASE'" 182 | echo "- You are now on branch '$BRANCH'" 183 | echo 184 | } 185 | -------------------------------------------------------------------------------- /git-flow-version: -------------------------------------------------------------------------------- 1 | # 2 | # git-flow -- A collection of Git extensions to provide high-level 3 | # repository operations for Vincent Driessen's branching model. 4 | # 5 | # Original blog post presenting this model is found at: 6 | # http://nvie.com/git-model 7 | # 8 | # Feel free to contribute to this project at: 9 | # http://github.com/nvie/gitflow 10 | # 11 | # Copyright 2010 Vincent Driessen. All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or without 14 | # modification, are permitted provided that the following conditions are met: 15 | # 16 | # 1. Redistributions of source code must retain the above copyright notice, 17 | # this list of conditions and the following disclaimer. 18 | # 19 | # 2. Redistributions in binary form must reproduce the above copyright 20 | # notice, this list of conditions and the following disclaimer in the 21 | # documentation and/or other materials provided with the distribution. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 24 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 26 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 30 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 32 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | # 34 | # The views and conclusions contained in the software and documentation are 35 | # those of the authors and should not be interpreted as representing official 36 | # policies, either expressed or implied, of Vincent Driessen. 37 | # 38 | 39 | GITFLOW_VERSION=0.4.2-pre 40 | 41 | usage() { 42 | echo "usage: git flow version" 43 | } 44 | 45 | cmd_default() { 46 | echo "$GITFLOW_VERSION" 47 | } 48 | 49 | cmd_help() { 50 | usage 51 | exit 0 52 | } 53 | -------------------------------------------------------------------------------- /gitflow-common: -------------------------------------------------------------------------------- 1 | # 2 | # git-flow -- A collection of Git extensions to provide high-level 3 | # repository operations for Vincent Driessen's branching model. 4 | # 5 | # Original blog post presenting this model is found at: 6 | # http://nvie.com/git-model 7 | # 8 | # Feel free to contribute to this project at: 9 | # http://github.com/nvie/gitflow 10 | # 11 | # Copyright 2010 Vincent Driessen. All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or without 14 | # modification, are permitted provided that the following conditions are met: 15 | # 16 | # 1. Redistributions of source code must retain the above copyright notice, 17 | # this list of conditions and the following disclaimer. 18 | # 19 | # 2. Redistributions in binary form must reproduce the above copyright 20 | # notice, this list of conditions and the following disclaimer in the 21 | # documentation and/or other materials provided with the distribution. 22 | # 23 | # THIS SOFTWARE IS PROVIDED BY VINCENT DRIESSEN ``AS IS'' AND ANY EXPRESS OR 24 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 25 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 26 | # EVENT SHALL VINCENT DRIESSEN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 | # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 30 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 32 | # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | # 34 | # The views and conclusions contained in the software and documentation are 35 | # those of the authors and should not be interpreted as representing official 36 | # policies, either expressed or implied, of Vincent Driessen. 37 | # 38 | 39 | # 40 | # Common functionality 41 | # 42 | 43 | # shell output 44 | warn() { echo "$@" >&2; } 45 | die() { warn "$@"; exit 1; } 46 | 47 | escape() { 48 | echo "$1" | sed 's/\([\.\$\*]\)/\\\1/g' 49 | } 50 | 51 | # set logic 52 | has() { 53 | local item=$1; shift 54 | echo " $@ " | grep -q " $(escape $item) " 55 | } 56 | 57 | # basic math 58 | min() { [ "$1" -le "$2" ] && echo "$1" || echo "$2"; } 59 | max() { [ "$1" -ge "$2" ] && echo "$1" || echo "$2"; } 60 | 61 | # basic string matching 62 | startswith() { [ "$1" != "${1#$2}" ]; } 63 | endswith() { [ "$1" != "${1%$2}" ]; } 64 | 65 | # convenience functions for checking shFlags flags 66 | flag() { local FLAG; eval FLAG='$FLAGS_'$1; [ $FLAG -eq $FLAGS_TRUE ]; } 67 | noflag() { local FLAG; eval FLAG='$FLAGS_'$1; [ $FLAG -ne $FLAGS_TRUE ]; } 68 | 69 | # 70 | # Git specific common functionality 71 | # 72 | 73 | git_do() { 74 | # equivalent to git, used to indicate actions that make modifications 75 | if flag show_commands; then 76 | echo "git $@" >&2 77 | fi 78 | git "$@" 79 | } 80 | 81 | git_local_branches() { git branch --no-color | sed 's/^[* ] //'; } 82 | git_remote_branches() { git branch -r --no-color | sed 's/^[* ] //'; } 83 | git_all_branches() { ( git branch --no-color; git branch -r --no-color) | sed 's/^[* ] //'; } 84 | git_all_tags() { git tag; } 85 | 86 | git_current_branch() { 87 | git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g' 88 | } 89 | 90 | git_is_clean_working_tree() { 91 | if ! git diff --no-ext-diff --ignore-submodules --quiet --exit-code; then 92 | return 1 93 | elif ! git diff-index --cached --quiet --ignore-submodules HEAD --; then 94 | return 2 95 | else 96 | return 0 97 | fi 98 | } 99 | 100 | git_repo_is_headless() { 101 | ! git rev-parse --quiet --verify HEAD >/dev/null 2>&1 102 | } 103 | 104 | git_local_branch_exists() { 105 | has $1 $(git_local_branches) 106 | } 107 | 108 | git_remote_branch_exists() { 109 | has $1 $(git_remote_branches) 110 | } 111 | 112 | git_branch_exists() { 113 | has $1 $(git_all_branches) 114 | } 115 | 116 | git_tag_exists() { 117 | has $1 $(git_all_tags) 118 | } 119 | 120 | # 121 | # git_compare_branches() 122 | # 123 | # Tests whether branches and their "origin" counterparts have diverged and need 124 | # merging first. It returns error codes to provide more detail, like so: 125 | # 126 | # 0 Branch heads point to the same commit 127 | # 1 First given branch needs fast-forwarding 128 | # 2 Second given branch needs fast-forwarding 129 | # 3 Branch needs a real merge 130 | # 4 There is no merge base, i.e. the branches have no common ancestors 131 | # 132 | git_compare_branches() { 133 | local commit1=$(git rev-parse "$1") 134 | local commit2=$(git rev-parse "$2") 135 | if [ "$commit1" != "$commit2" ]; then 136 | local base=$(git merge-base "$commit1" "$commit2") 137 | if [ $? -ne 0 ]; then 138 | return 4 139 | elif [ "$commit1" = "$base" ]; then 140 | return 1 141 | elif [ "$commit2" = "$base" ]; then 142 | return 2 143 | else 144 | return 3 145 | fi 146 | else 147 | return 0 148 | fi 149 | } 150 | 151 | # 152 | # git_is_branch_merged_into() 153 | # 154 | # Checks whether branch $1 is succesfully merged into $2 155 | # 156 | git_is_branch_merged_into() { 157 | local subject=$1 158 | local base=$2 159 | local all_merges="$(git branch --no-color --contains $subject | sed 's/^[* ] //')" 160 | has $base $all_merges 161 | } 162 | 163 | # 164 | # gitflow specific common functionality 165 | # 166 | 167 | # check if this repo has been inited for gitflow 168 | gitflow_has_master_configured() { 169 | local master=$(git config --get gitflow.branch.master) 170 | [ "$master" != "" ] && git_local_branch_exists "$master" 171 | } 172 | 173 | gitflow_has_develop_configured() { 174 | local develop=$(git config --get gitflow.branch.develop) 175 | [ "$develop" != "" ] && git_local_branch_exists "$develop" 176 | } 177 | 178 | gitflow_has_prefixes_configured() { 179 | git config --get gitflow.prefix.feature >/dev/null 2>&1 && \ 180 | git config --get gitflow.prefix.release >/dev/null 2>&1 && \ 181 | git config --get gitflow.prefix.hotfix >/dev/null 2>&1 && \ 182 | git config --get gitflow.prefix.support >/dev/null 2>&1 && \ 183 | git config --get gitflow.prefix.versiontag >/dev/null 2>&1 184 | } 185 | 186 | gitflow_is_initialized() { 187 | gitflow_has_master_configured && \ 188 | gitflow_has_develop_configured && \ 189 | [ "$(git config --get gitflow.branch.master)" != \ 190 | "$(git config --get gitflow.branch.develop)" ] && \ 191 | gitflow_has_prefixes_configured 192 | } 193 | 194 | # loading settings that can be overridden using git config 195 | gitflow_load_settings() { 196 | export DOT_GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) 197 | export MASTER_BRANCH=$(git config --get gitflow.branch.master) 198 | export DEVELOP_BRANCH=$(git config --get gitflow.branch.develop) 199 | export ORIGIN=$(git config --get gitflow.origin || echo origin) 200 | } 201 | 202 | # 203 | # gitflow_resolve_nameprefix 204 | # 205 | # Inputs: 206 | # $1 = name prefix to resolve 207 | # $2 = branch prefix to use 208 | # 209 | # Searches branch names from git_local_branches() to look for a unique 210 | # branch name whose name starts with the given name prefix. 211 | # 212 | # There are multiple exit codes possible: 213 | # 0: The unambiguous full name of the branch is written to stdout 214 | # (success) 215 | # 1: No match is found. 216 | # 2: Multiple matches found. These matches are written to stderr 217 | # 218 | gitflow_resolve_nameprefix() { 219 | local name=$1 220 | local prefix=$2 221 | local matches 222 | local num_matches 223 | 224 | # first, check if there is a perfect match 225 | if git_local_branch_exists "$prefix$name"; then 226 | echo "$name" 227 | return 0 228 | fi 229 | 230 | matches=$(echo "$(git_local_branches)" | grep "^$(escape "$prefix$name")") 231 | num_matches=$(echo "$matches" | wc -l) 232 | if [ -z "$matches" ]; then 233 | # no prefix match, so take it literally 234 | warn "No branch matches prefix '$name'" 235 | return 1 236 | else 237 | if [ $num_matches -eq 1 ]; then 238 | echo "${matches#$prefix}" 239 | return 0 240 | else 241 | # multiple matches, cannot decide 242 | warn "Multiple branches match prefix '$name':" 243 | for match in $matches; do 244 | warn "- $match" 245 | done 246 | return 2 247 | fi 248 | fi 249 | } 250 | 251 | # 252 | # Assertions for use in git-flow subcommands 253 | # 254 | 255 | require_git_repo() { 256 | if ! git rev-parse --git-dir >/dev/null 2>&1; then 257 | die "fatal: Not a git repository" 258 | fi 259 | } 260 | 261 | require_gitflow_initialized() { 262 | if ! gitflow_is_initialized; then 263 | die "fatal: Not a gitflow-enabled repo yet. Please run \"git flow init\" first." 264 | fi 265 | } 266 | 267 | require_clean_working_tree() { 268 | git_is_clean_working_tree 269 | local result=$? 270 | if [ $result -eq 1 ]; then 271 | die "fatal: Working tree contains unstaged changes. Aborting." 272 | fi 273 | if [ $result -eq 2 ]; then 274 | die "fatal: Index contains uncommited changes. Aborting." 275 | fi 276 | } 277 | 278 | require_local_branch() { 279 | if ! git_local_branch_exists $1; then 280 | die "fatal: Local branch '$1' does not exist and is required." 281 | fi 282 | } 283 | 284 | require_remote_branch() { 285 | if ! has $1 $(git_remote_branches); then 286 | die "Remote branch '$1' does not exist and is required." 287 | fi 288 | } 289 | 290 | require_branch() { 291 | if ! has $1 $(git_all_branches); then 292 | die "Branch '$1' does not exist and is required." 293 | fi 294 | } 295 | 296 | require_branch_absent() { 297 | if has $1 $(git_all_branches); then 298 | die "Branch '$1' already exists. Pick another name." 299 | fi 300 | } 301 | 302 | require_tag_absent() { 303 | for tag in $(git_all_tags); do 304 | if [ "$1" = "$tag" ]; then 305 | die "Tag '$1' already exists. Pick another name." 306 | fi 307 | done 308 | } 309 | 310 | require_branches_equal() { 311 | require_local_branch "$1" 312 | require_remote_branch "$2" 313 | git_compare_branches "$1" "$2" 314 | local status=$? 315 | if [ $status -gt 0 ]; then 316 | warn "Branches '$1' and '$2' have diverged." 317 | if [ $status -eq 1 ]; then 318 | die "And branch '$1' may be fast-forwarded." 319 | elif [ $status -eq 2 ]; then 320 | # Warn here, since there is no harm in being ahead 321 | warn "And local branch '$1' is ahead of '$2'." 322 | else 323 | die "Branches need merging first." 324 | fi 325 | fi 326 | } 327 | -------------------------------------------------------------------------------- /gitflow-shFlags: -------------------------------------------------------------------------------- 1 | shFlags/src/shflags --------------------------------------------------------------------------------