1# $Id$ 2# vim:et:ft=sh:sts=2:sw=2 3# 4# git-flow -- A collection of Git extensions to provide high-level 5# repository operations for Vincent Driessen's branching model. 6# 7# A blog post presenting this model is found at: 8# http://blog.avirtualhome.com/development-workflow-using-git/ 9# 10# Feel free to contribute to this project at: 11# http://github.com/petervanderdoes/gitflow 12# 13# Authors: 14# Copyright 2012-2019 Peter van der Does. All rights reserved. 15# 16# Original Author: 17# Copyright 2010 Vincent Driessen. All rights reserved. 18# 19# Redistribution and use in source and binary forms, with or without 20# modification, are permitted provided that the following conditions are met: 21# 22# 1. Redistributions of source code must retain the above copyright notice, this 23# list of conditions and the following disclaimer. 24# 2. Redistributions in binary form must reproduce the above copyright notice, 25# this list of conditions and the following disclaimer in the documentation 26# and/or other materials provided with the distribution. 27# 28# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 29# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 32# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 33# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 34# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 35# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 37# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38# 39 40# 41# Function used by finish command to actually finish the release branch 42# Called when the base of the release is the $DEVELOP_BRANCH 43# 44_finish_from_develop() { 45 local opts merge_branch commit keepmsg remotebranchdeleted localbranchdeleted compare_refs_result merge_result 46 47 remotebranchdeleted=$FLAGS_FALSE 48 localbranchdeleted=$FLAGS_FALSE 49 50 # Update local branches with remote branches 51 if flag fetch; then 52 git_fetch_branch "$ORIGIN" "$MASTER_BRANCH" 53 git_fetch_branch "$ORIGIN" "$DEVELOP_BRANCH" 54 fi 55 56 # Check if the local branches have all the commits from the remote branches 57 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 58 require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH" 59 fi 60 if git_remote_branch_exists "$ORIGIN/$MASTER_BRANCH"; then 61 if flag ff_master; then 62 git_compare_refs "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH" 63 compare_refs_result=$? 64 65 if [ $compare_refs_result -gt 0 ]; then 66 warn "Branches '"$MASTER_BRANCH"' and '"$ORIGIN/$MASTER_BRANCH"' have diverged." 67 if [ $compare_refs_result -eq 1 ]; then 68 warn "Fast forwarding '"$MASTER_BRANCH"'." 69 git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'." 70 git_do merge --ff-only "$ORIGIN/$MASTER_BRANCH" >/dev/null 2>&1 71 merge_result=$? 72 git_do checkout "$BRANCH" 73 if [ $merge_result -gt 0 ]; then 74 die "'"$MASTER_BRANCH"' can not be fast forwarded." 75 fi 76 elif [ $compare_refs_result -eq 2 ]; then 77 # Warn here, since there is no harm in being ahead 78 warn "And local branch '$1' is ahead of '$2'." 79 else 80 die "Branches need merging first." 81 fi 82 fi 83 else 84 require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH" 85 fi 86 fi 87 if git_remote_branch_exists "$ORIGIN/$DEVELOP_BRANCH"; then 88 require_branches_equal "$DEVELOP_BRANCH" "$ORIGIN/$DEVELOP_BRANCH" 89 fi 90 91 if noflag notag; then 92 # We ask for a tag, be sure it does not exists or 93 # points to the latest hotfix commit 94 if git_tag_exists "$VERSION_PREFIX$TAGNAME"; then 95 git_compare_refs "$BRANCH" "$VERSION_PREFIX$TAGNAME"^2 2>/dev/null 96 [ $? -eq 0 ] || die "Tag already exists and does not point to release branch '$BRANCH'" 97 fi 98 fi 99 100 run_pre_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH" 101 102 # Try to merge into master. 103 # In case a previous attempt to finish this release branch has failed, 104 # but the merge into master was successful, we skip it now 105 if ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then 106 git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'." 107 if noflag squash; then 108 git_do merge --no-ff "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now? 109 else 110 git_do merge --squash "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now? 111 flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$MASTER_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG" 112 git_do commit 113 fi 114 fi 115 116 if noflag notag; then 117 # Try to tag the release. 118 # In case a previous attempt to finish this release branch has failed, 119 # but the tag was set successful, we skip it now 120 if ! git_tag_exists "$VERSION_PREFIX$TAGNAME"; then 121 git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'." 122 if [ "$FLAGS_message" != "" ] && [ "$FLAGS_messagefile" != "" ]; then 123 die "Use either -m,--message or -f,--messagefile. Can not use both options at the same time" 124 fi 125 opts="-a" 126 flag sign && opts="$opts -s" 127 [ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'" 128 if [ "$FLAGS_message" != "" ]; then 129 # Run filter on the tag message 130 FLAGS_message=$(run_filter_hook release-finish-tag-message "${FLAGS_message}" "$VERSION_PREFIX$TAGNAME") 131 opts="$opts -m '$FLAGS_message'" 132 fi 133 [ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'" 134 eval git_do tag $opts "$VERSION_PREFIX$TAGNAME" || die "Tagging failed. Please run finish again to retry." 135 fi 136 fi 137 138 # By default we backmerge the $MASTER_BRANCH unless the user explicitly 139 # stated not to do a back merge, in that case we use the $BRANCH. 140 if noflag nobackmerge; then 141 merge_branch="$MASTER_BRANCH" 142 else 143 merge_branch="$BRANCH" 144 fi 145 146 # Try to merge into develop unless 'nodevelopmerge' has been specified. 147 # In case a previous attempt to finish this release branch has failed, 148 # but the merge into develop was successful, we skip it now 149 if noflag nodevelopmerge; then 150 if ! git_is_branch_merged_into "$merge_branch" "$DEVELOP_BRANCH"; then 151 git_do checkout "$DEVELOP_BRANCH" || die "Could not check out branch '$DEVELOP_BRANCH'." 152 153 if noflag nobackmerge; then 154 # Accounting for 'git describe', if a release is tagged 155 # we use the tag commit instead of the branch. 156 if noflag notag; then 157 commit="$VERSION_PREFIX$TAGNAME" 158 else 159 commit="$MASTER_BRANCH" 160 fi 161 git_do merge --no-ff "$commit" || die "There were merge conflicts." # TODO: What do we do now? 162 else 163 commit="$BRANCH" 164 if noflag squash; then 165 git_do merge --no-ff "$commit" || die "There were merge conflicts." # TODO: What do we do now? 166 else 167 git_do merge --squash "$commit" || die "There were merge conflicts." # TODO: What do we do now? 168 flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$DEVELOP_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG" 169 git_do commit 170 fi 171 fi 172 fi 173 fi 174 175 run_post_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH" 176 177 if flag push; then 178 if flag pushdevelop; then 179 git_do push "$ORIGIN" "$DEVELOP_BRANCH" || die "Could not push branch '$DEVELOP_BRANCH' to remote '$ORIGIN'." 180 fi 181 if flag pushproduction; then 182 git_do push "$ORIGIN" "$MASTER_BRANCH" || die "Could not push branch '$MASTER_BRANCH' to remote '$ORIGIN'." 183 fi 184 if noflag notag && flag pushtag; then 185 git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'." 186 fi 187 fi 188 189 # Delete branch 190 if noflag keep; then 191 192 if [ "$BRANCH" = "$(git_current_branch)" ]; then 193 git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'." 194 fi 195 196 # Always delete remote first 197 if noflag keepremote;then 198 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 199 git_remote_branch_delete "$BRANCH" && remotebranchdeleted=$FLAGS_TRUE 200 fi 201 fi 202 203 # Delete local after remote to avoid warnings 204 if noflag keeplocal; then 205 if flag force_delete; then 206 git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE 207 else 208 if noflag squash; then 209 git_do branch -d "$BRANCH" && localbranchdeleted=$FLAGS_TRUE 210 else 211 git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE 212 fi 213 fi 214 fi 215 216 # no more branches: we can safely remove config section 217 if ! git_remote_branch_exists "$ORIGIN/$BRANCH" -a ! git_local_branch_exists "$BRANCH"; then 218 gitflow_config_remove_base_section "$BRANCH" 219 fi 220 fi 221 222 echo 223 echo "Summary of actions:" 224 if flag fetch; then 225 echo "- Latest objects have been fetched from '$ORIGIN'" 226 fi 227 echo "- Release branch '$BRANCH' has been merged into '$MASTER_BRANCH'" 228 if noflag notag; then 229 echo "- The release was tagged '$VERSION_PREFIX$TAGNAME'" 230 fi 231 [ "$commit" = "$MASTER_BRANCH" ] && echo "- Master branch '$MASTER_BRANCH' has been back-merged into '$DEVELOP_BRANCH'" 232 [ "$commit" = "$VERSION_PREFIX$TAGNAME" ] && echo "- Release tag '$VERSION_PREFIX$TAGNAME' has been back-merged into '$DEVELOP_BRANCH'" 233 [ "$commit" = "$BRANCH" ] && echo "- Release branch '$BRANCH' has been merged into '$DEVELOP_BRANCH'" 234 235 if noflag keep; then 236 if [ $localbranchdeleted -eq $FLAGS_TRUE ]; then 237 keepmsg="has been locally deleted" 238 else 239 keepmsg="is still locally available" 240 fi 241 if [ $remotebranchdeleted -eq $FLAGS_TRUE ]; then 242 keepmsg=$keepmsg"; it has been remotely deleted from '$ORIGIN'" 243 elif git_remote_branch_exists "$ORIGIN/$BRANCH"; then 244 keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'" 245 fi 246 else 247 keepmsg="is still locally available" 248 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 249 keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'" 250 fi 251 fi 252 echo "- Release branch '$BRANCH' "$keepmsg 253 254 if flag push; then 255 echo "- '$DEVELOP_BRANCH', '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'" 256 fi 257 echo "- You are now on branch '$(git_current_branch)'" 258 echo 259} 260 261# 262# Function used by finish command to actually finish the release branch 263# Called when the base of the release is NOT the $DEVELOP_BRANCH 264# 265 266_finish_base() { 267 local opts merge_branch commit keepmsg localbranchdeleted remotebranchdeleted 268 269 remotebranchdeleted=$FLAGS_FALSE 270 localbranchdeleted=$FLAGS_FALSE 271 272 # Update local branches with remote branches 273 if flag fetch; then 274 git_fetch_branch "$ORIGIN" "$BASE_BRANCH" 275 fi 276 277 # Check if the local branches have all the commits from the remote branches 278 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 279 require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH" 280 fi 281 if git_remote_branch_exists "$ORIGIN/$BASE_BRANCH"; then 282 require_branches_equal "$BASE_BRANCH" "$ORIGIN/$BASE_BRANCH" 283 fi 284 285 if noflag notag; then 286 # We ask for a tag, be sure it does not exists or 287 # points to the latest hotfix commit 288 if git_tag_exists "$VERSION_PREFIX$TAGNAME"; then 289 git_compare_refs "$BRANCH" "$VERSION_PREFIX$TAGNAME"^2 2>/dev/null 290 [ $? -eq 0 ] || die "Tag already exists and does not point to release branch '$BRANCH'" 291 fi 292 fi 293 294 run_pre_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH" 295 296 # Try to merge into base branch. 297 # In case a previous attempt to finish this release branch has failed, 298 # but the merge into develop was successful, we skip it now 299 if ! git_is_branch_merged_into "$BRANCH" "$BASE_BRANCH"; then 300 git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'." 301 if noflag squash; then 302 git_do merge --no-ff "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now? 303 else 304 git_do merge --squash "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now? 305 flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$BASE_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG" 306 git_do commit 307 fi 308 fi 309 310 if noflag notag; then 311 # Try to tag the release. 312 # In case a previous attempt to finish this release branch has failed, 313 # but the tag was set successful, we skip it now 314 if ! git_tag_exists "$VERSION_PREFIX$TAGNAME"; then 315 git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'." 316 if [ "$FLAGS_message" != "" ] && [ "$FLAGS_messagefile" != "" ]; then 317 die "Use either -m,--message or -f,--messagefile. Can not use both options at the same time" 318 fi 319 opts="-a" 320 flag sign && opts="$opts -s" 321 [ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'" 322 if [ "$FLAGS_message" != "" ]; then 323 # Run filter on the tag message 324 FLAGS_message=$(run_filter_hook release-finish-tag-message "${FLAGS_message}" "$VERSION_PREFIX$TAGNAME") 325 opts="$opts -m '$FLAGS_message'" 326 fi 327 [ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'" 328 eval git_do tag $opts "$VERSION_PREFIX$TAGNAME" || die "Tagging failed. Please run finish again to retry." 329 fi 330 fi 331 332 run_post_hook "$VERSION_PREFIX$TAGNAME" "$ORIGIN" "$BRANCH" 333 334 # Delete branch 335 if noflag keep; then 336 337 # Always delete remote first 338 if noflag keepremote;then 339 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 340 git_remote_branch_delete "$BRANCH" && remotebranchdeleted=$FLAGS_TRUE 341 fi 342 fi 343 344 # Delete local after remote to avoid warnings 345 if noflag keeplocal; then 346 if [ "$BRANCH" = "$(git_current_branch)" ]; then 347 git_do checkout "$BASE_BRANCH" || die "Could not check out branch '$BASE_BRANCH'." 348 fi 349 if flag force_delete; then 350 git_do branch -D "$BRANCH" && localbranchdeleted=$FLAGS_TRUE 351 else 352 git_do branch -d "$BRANCH" && localbranchdeleted=$FLAGS_TRUE 353 fi 354 fi 355 356 # no more branches: we can safely remove config section 357 if ! git_remote_branch_exists "$ORIGIN/$BRANCH" -a ! git_local_branch_exists "$BRANCH"; then 358 gitflow_config_remove_base_section "$BRANCH" 359 fi 360 fi 361 362 if flag push; then 363 if flag pushdevelop; then 364 git_do push "$ORIGIN" "$BASE_BRANCH" || die "Could not push branch '$BASE_BRANCH' to remote '$ORIGIN'." 365 fi 366 if noflag notag && flag pushtag; then 367 git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'." 368 fi 369 fi 370 371 echo 372 echo "Summary of actions:" 373 if flag fetch; then 374 echo "- Latest objects have been fetched from '$ORIGIN'" 375 fi 376 if noflag notag; then 377 echo "- The release was tagged '$VERSION_PREFIX$TAGNAME'" 378 fi 379 [ "$commit" = "$VERSION_PREFIX$TAGNAME" ] && echo "- Release tag '$VERSION_PREFIX$TAGNAME' has been merged into '$BASE_BRANCH'" 380 [ "$commit" = "$BRANCH" ] && echo "- Release branch '$BRANCH' has been merged into '$BASE_BRANCH'" 381 if noflag keep; then 382 if [ $localbranchdeleted -eq $FLAGS_TRUE ]; then 383 keepmsg="has been locally deleted" 384 else 385 keepmsg="is still locally available" 386 fi 387 if [ $remotebranchdeleted -eq $FLAGS_TRUE ]; then 388 keepmsg=$keepmsg"; it has been remotely deleted from '$ORIGIN'" 389 elif git_remote_branch_exists "$ORIGIN/$BRANCH"; then 390 keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'" 391 fi 392 else 393 keepmsg="is still locally available" 394 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 395 keepmsg=$keepmsg"; it is still remotely available on '$ORIGIN'" 396 fi 397 fi 398 echo "- Release branch '$BRANCH' "$keepmsg 399 400 if flag push; then 401 echo "- '$BASE_BRANCH' and tags have been pushed to '$ORIGIN'" 402 fi 403 echo "- You are now on branch '$(git_current_branch)'" 404 echo 405} 406initialize() { 407 require_git_repo 408 require_gitflow_initialized 409 git config --get gitflow.prefix.release >/dev/null 2>&1 || die "Release prefix not set. Please run 'git flow init'." 410 gitflow_load_settings 411 VERSION_PREFIX=$(git config --get gitflow.prefix.versiontag) 412 PREFIX=$(git config --get gitflow.prefix.release) 413} 414 415usage() { 416 OPTIONS_SPEC="\ 417git flow release [list] 418git flow release start 419git flow release finish 420git flow release publish 421git flow release track 422git flow release delete 423 424Manage your release branches. 425 426For more specific help type the command followed by --help 427-- 428" 429 flags_help 430} 431 432cmd_default() { 433 cmd_list "$@" 434} 435 436cmd_list() { 437 OPTIONS_SPEC="\ 438git flow release [list] [-h] [-v] 439 440List existing release branches 441-- 442h,help! Show this help 443v,verbose! verbose (more) output 444" 445 local release_branches current_branch 446 local width branch len 447 local base develop_sha branch_sha nicename 448 449 # cmd_default may already define flags 450 # at this stage we can not use parse_args 451 if [ -z "${FLAGS_verbose}" ]; then 452 DEFINE_boolean 'verbose' false 'verbose (more) output' v 453 fi 454 455 # Parse arguments 456 parse_args "$@" 457 458 release_branches=$(git_local_branches_prefixed "$PREFIX") 459 if [ -z "$release_branches" ]; then 460 warn "No release branches exist." 461 warn "" 462 warn "You can start a new release branch:" 463 warn "" 464 warn " git flow release start <name> [<base>]" 465 warn "" 466 exit 0 467 fi 468 469 current_branch=$(git_current_branch) 470 471 # Determine column width first 472 width=0 473 for branch in $release_branches; do 474 len=${#branch} 475 width=$(max $width $len) 476 done 477 width=$(($width+3-${#PREFIX})) 478 479 for branch in $release_branches; do 480 base=$(git merge-base "$branch" "$DEVELOP_BRANCH") 481 develop_sha=$(git rev-parse "$DEVELOP_BRANCH") 482 branch_sha=$(git rev-parse "$branch") 483 if [ "$branch" = "$current_branch" ]; then 484 printf "* " 485 else 486 printf " " 487 fi 488 if flag verbose; then 489 printf "%-${width}s" "${branch#$PREFIX}" 490 if [ "$branch_sha" = "$develop_sha" ]; then 491 printf "(no commits yet)" 492 else 493 nicename=$(git rev-parse --short "$base") 494 printf "(based on $nicename)" 495 fi 496 else 497 printf "%s" "${branch#$PREFIX}" 498 fi 499 echo 500 done 501} 502 503cmd_help() { 504 usage 505 exit 0 506} 507 508# Parse arguments and set common variables 509parse_args() { 510 FLAGS "$@" || exit $? 511 eval set -- "${FLAGS_ARGV}" 512 513 # Read arguments into global variables 514 if [ -z $1 ]; then 515 VERSION='' 516 else 517 VERSION=$1 518 fi 519 BRANCH=$PREFIX$VERSION 520} 521 522require_no_existing_release_branches() { 523 local release_branches first_branch 524 525 release_branches=$(git_local_branches_prefixed "$PREFIX") 526 first_branch=$(echo ${release_branches} | head -n1) 527 528 first_branch=${first_branch#$PREFIX} 529 [ -z "$release_branches" ] || die "There is an existing release branch '$first_branch'. Finish that one first." 530} 531 532cmd_start() { 533 OPTIONS_SPEC="\ 534git flow release start [options] <version> [<base>] 535 536Start a new release branch 537-- 538h,help! Show this help 539showcommands! Show git commands while executing them 540F,[no]fetch Fetch from $ORIGIN before performing finish 541v,verbose! Verbose (more) output 542" 543 local base 544 545 # Define flags 546 DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F 547 548 # Override defaults with values from config 549 gitflow_override_flag_boolean "release.start.fetch" "fetch" 550 551 # Parse arguments 552 parse_args "$@" 553 eval set -- "${FLAGS_ARGV}" 554 base=${2:-$DEVELOP_BRANCH} 555 556 # Run filter on the version 557 VERSION=$(run_filter_hook release-start-version $VERSION) 558 if [ $? -eq 127 ]; then 559 die $VERSION 560 fi 561 562 # As VERSION might have changed reset BRANCH with new VERSION 563 BRANCH=$PREFIX$VERSION 564 565 require_base_is_local_branch "$base" 566 gitflow_require_version_arg 567 568 require_no_existing_release_branches 569 570 # Sanity checks 571 git_config_bool_exists "gitflow.allowdirty" || require_clean_working_tree 572 require_branch_absent "$BRANCH" 573 require_tag_absent "$VERSION_PREFIX$VERSION" 574 if flag fetch; then 575 git_fetch_branch "$ORIGIN" "$base" 576 fi 577 if git_remote_branch_exists "$ORIGIN/$base"; then 578 require_branches_equal "$base" "$ORIGIN/$base" 579 fi 580 581 run_pre_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH" "$base" 582 583 gitflow_config_set_base_branch $base $BRANCH 584 585 # Create branch 586 git_do checkout -b "$BRANCH" "$base" || die "Could not create release branch '$BRANCH'." 587 588 run_post_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH" "$base" 589 590 echo 591 echo "Summary of actions:" 592 echo "- A new branch '$BRANCH' was created, based on '$base'" 593 echo "- You are now on branch '$(git_current_branch)'" 594 echo 595 echo "Follow-up actions:" 596 echo "- Bump the version number now!" 597 echo "- Start committing last-minute fixes in preparing your release" 598 echo "- When done, run:" 599 echo 600 echo " git flow release finish '$VERSION'" 601 echo 602} 603 604cmd_finish() { 605 OPTIONS_SPEC="\ 606git flow release finish [-h] [-F] [-s] [-u] [-m | -f] [-p] [-k] [-n] [-b] [-S] <version> 607 608 609Finish a release branch 610-- 611h,help Show this help 612showcommands! Show git commands while executing them 613F,[no]fetch Fetch from origin before performing finish 614s,sign! Sign the release tag cryptographically 615u,signingkey! Use the given GPG-key for the digital signature (implies -s) 616m,message! Use the given tag message 617f,[no]messagefile= Use the contents of the given file as a tag message 618p,[no]push Push to origin after performing finish 619[no]pushproduction Push the production branch 620[no]pushdevelop Push the develop branch 621[no]pushtag Push the tag 622k,[no]keep Keep branch after performing finish 623[no]keepremote Keep the remote branch 624[no]keeplocal Keep the local branch 625D,[no]force_delete Force delete release branch after finish 626n,[no]tag Don't tag this release 627b,[no]nobackmerge Don't back-merge master, or tag if applicable, in develop 628S,[no]squash Squash release during merge 629[no]ff-master Fast forward master branch if possible 630T,tagname! Use given tag name 631nodevelopmerge! Don't back-merge develop branch 632" 633 # Define flags 634 DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F 635 DEFINE_boolean 'sign' false "sign the release tag cryptographically" s 636 DEFINE_string 'signingkey' "" "use the given GPG-key for the digital signature (implies -s)" u 637 DEFINE_string 'message' "" "use the given tag message" m 638 DEFINE_string 'messagefile' "" "use the contents of the given file as a tag message" f 639 DEFINE_boolean 'push' false "push to $ORIGIN after performing finish" p 640 DEFINE_boolean 'pushproduction' false "push the production branch" 641 DEFINE_boolean 'pushdevelop' false "push the develop branch" 642 DEFINE_boolean 'pushtag' false "push the tag" 643 DEFINE_boolean 'keep' false "keep branch after performing finish" k 644 DEFINE_boolean 'keepremote' false "keep the remote branch" 645 DEFINE_boolean 'keeplocal' false "keep the local branch" 646 DEFINE_boolean 'force_delete' false "force delete release branch after finish" D 647 DEFINE_boolean 'notag' false "don't tag this release" n 648 DEFINE_boolean 'nobackmerge' false "don't back-merge $MASTER_BRANCH, or tag if applicable, in $DEVELOP_BRANCH " b 649 DEFINE_boolean 'squash' false "squash release during merge" S 650 DEFINE_boolean 'squash-info' false "add branch info during squash" 651 DEFINE_boolean 'ff-master' false "fast forward master branch if possible" 652 DEFINE_string 'tagname' "" "use the given tag name" T 653 DEFINE_boolean 'nodevelopmerge' false "don't merge $BRANCH into $DEVELOP_BRANCH " 654 655 # Override defaults with values from config 656 gitflow_override_flag_boolean "release.finish.fetch" "fetch" 657 gitflow_override_flag_boolean "release.finish.sign" "sign" 658 gitflow_override_flag_boolean "release.finish.push" "push" 659 gitflow_override_flag_boolean "release.finish.pushproduction" "pushproduction" 660 gitflow_override_flag_boolean "release.finish.pushdevelop" "pushdevelop" 661 gitflow_override_flag_boolean "release.finish.pushtag" "pushtag" 662 gitflow_override_flag_boolean "release.finish.keep" "keep" 663 gitflow_override_flag_boolean "release.finish.keepremote" "keepremote" 664 gitflow_override_flag_boolean "release.finish.keeplocal" "keeplocal" 665 gitflow_override_flag_boolean "release.finish.force-delete" "force_delete" 666 gitflow_override_flag_boolean "release.finish.notag" "notag" 667 gitflow_override_flag_boolean "release.finish.nobackmerge" "nobackmerge" 668 gitflow_override_flag_boolean "release.finish.squash" "squash" 669 gitflow_override_flag_boolean "release.finish.squash-info" "squash_info" 670 gitflow_override_flag_boolean "release.finish.ff-master" "ff-master" 671 gitflow_override_flag_string "release.finish.signingkey" "signingkey" 672 gitflow_override_flag_string "release.finish.message" "message" 673 gitflow_override_flag_string "release.finish.messagefile" "messagefile" 674 gitflow_override_flag_boolean "release.finish.nodevelopmerge" "nodevelopmerge" 675 676 # Parse arguments 677 parse_args "$@" 678 679 # Use current branch if no version is given 680 if [ "$VERSION" = "" ]; then 681 gitflow_use_current_branch_version 682 fi 683 684 685 # Run filter on the version 686 VERSION=$(run_filter_hook release-finish-version $VERSION) 687 if [ $? -eq 127 ]; then 688 die $VERSION 689 fi 690 691 # Use branch name if no tag name is given 692 if [ "$FLAGS_tagname" != "" ]; then 693 TAGNAME=$FLAGS_tagname 694 else 695 TAGNAME=$VERSION 696 fi 697 698 # As VERSION might have changed reset BRANCH with new VERSION 699 BRANCH=$PREFIX$VERSION 700 701 BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH) 702 BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH} 703 git_local_branch_exists "$BASE_BRANCH" || die "The base '$BASE_BRANCH' doesn't exists locally or is not a branch. Can't finish the release branch '$BRANCH'." 704 705 # Handle flags that imply other flags 706 if [ "$FLAGS_signingkey" != "" ]; then 707 FLAGS_sign=$FLAGS_TRUE 708 fi 709 710 # Keeping both branches implies the --keep flag to be true. 711 if flag keepremote && flag keeplocal; then 712 FLAGS_keep=$FLAGS_TRUE 713 fi 714 715 # Pushing implies we push all. 716 if flag push; then 717 FLAGS_pushproduction=$FLAGS_TRUE 718 FLAGS_pushdevelop=$FLAGS_TRUE 719 FLAGS_pushtag=$FLAGS_TRUE 720 fi 721 # If we push either of these it means we need to do a push 722 if flag pushproduction || flag pushdevelop || flag pushtag; then 723 FLAGS_push=$FLAGS_TRUE 724 fi 725 726 # Sanity checks 727 require_branch "$BRANCH" 728 require_clean_working_tree 729 730 # We always fetch the Branch from Origin 731 # This is done to avoid possible commits on the remote that are not 732 # merged into the local branch 733 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 734 git_fetch_branch "$ORIGIN" "$BRANCH" 735 fi 736 737 if [ "$BASE_BRANCH" = "$DEVELOP_BRANCH" ]; then 738 _finish_from_develop 739 else 740 _finish_base 741 fi 742} 743 744cmd_branch() { 745 OPTIONS_SPEC="\ 746git flow release branch [-h] [-F] [-s] [-u] [-m] [-f] [-p] [-n] [-S] <version> [<name>] 747 748 749Release a branch [<name>], if a name is not given it defaults to the develop branch, and use the given version <version> 750-- 751h,help Show this help 752showcommands! Show git commands while executing them 753F,[no]fetch Fetch from origin before performing finish 754s,sign! Sign the release tag cryptographically 755u,signingkey! Use the given GPG-key for the digital signature (implies -s) 756m,message! Use the given tag message 757f,[no]messagefile= Use the contents of the given file as a tag message 758p,[no]push Push to origin after performing finish 759n,[no]tag Don't tag this release 760S,[no]squash Squash release during merge 761" 762 local opts 763 764 # Define flags 765 DEFINE_boolean 'fetch' false "fetch from $ORIGIN before performing finish" F 766 DEFINE_boolean 'sign' false "sign the release tag cryptographically" s 767 DEFINE_string 'signingkey' "" "use the given GPG-key for the digital signature (implies -s)" u 768 DEFINE_string 'message' "" "use the given tag message" m 769 DEFINE_string 'messagefile' "" "use the contents of the given file as a tag message" f 770 DEFINE_boolean 'push' false "push to $ORIGIN after performing finish" p 771 DEFINE_boolean 'notag' false "don't tag this release" n 772 DEFINE_boolean 'squash' false "squash release during merge" S 773 DEFINE_boolean 'squash-info' false "add branch info during squash" 774 775 # Override defaults with values from config 776 gitflow_override_flag_boolean "release.branch.fetch" "fetch" 777 gitflow_override_flag_boolean "release.branch.sign" "sign" 778 gitflow_override_flag_boolean "release.branch.push" "push" 779 gitflow_override_flag_boolean "release.branch.notag" "notag" 780 gitflow_override_flag_boolean "release.branch.squash" "squash" 781 gitflow_override_flag_boolean "release.branch.squash-info" "squash_info" 782 gitflow_override_flag_string "release.branch.signingkey" "signingkey" 783 gitflow_override_flag_string "release.branch.message" "message" 784 gitflow_override_flag_string "release.branch.messagefile" "messagefile" 785 786 # Parse arguments 787 FLAGS "$@" || exit $? 788 eval set -- "${FLAGS_ARGV}" 789 790 # Read arguments into global variables 791 VERSION=$1 792 BRANCH=${2:-$DEVELOP_BRANCH} 793 794 # Run filter on the version 795 VERSION=$(run_filter_hook branch-finish-version $VERSION) 796 if [ $? -eq 127 ]; then 797 die $VERSION 798 fi 799 800 gitflow_require_version_arg 801 802 # Handle flags that imply other flags 803 if [ "$FLAGS_signingkey" != "" ]; then 804 FLAGS_sign=$FLAGS_TRUE 805 fi 806 807 # Sanity checks 808 if gitflow_is_prefixed_branch "$BRANCH"; then 809 die "Branch '$BRANCH' seems to be a git-flow branch. It's not allowed to release this directly." 810 fi 811 812 if [ "$BRANCH" = "$MASTER_BRANCH" ]; then 813 die "Can not release from the the master branch" 814 fi 815 816 require_branch "$BRANCH" 817 require_clean_working_tree 818 819 # We always fetch the Branch from Origin 820 # This is done to avoid possible commits on the remote that are not 821 # merged into the local branch 822 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 823 git_fetch_branch "$ORIGIN" "$BRANCH" 824 fi 825 826 # Update local branches with remote branches 827 if flag fetch; then 828 git_fetch_branch "$ORIGIN" "$MASTER_BRANCH" 829 fi 830 831 # Check if the local branches have all the commits from the remote branches 832 if git_remote_branch_exists "$ORIGIN/$BRANCH"; then 833 require_branches_equal "$BRANCH" "$ORIGIN/$BRANCH" 834 fi 835 if git_remote_branch_exists "$ORIGIN/$MASTER_BRANCH"; then 836 require_branches_equal "$MASTER_BRANCH" "$ORIGIN/$MASTER_BRANCH" 837 fi 838 839 run_pre_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH" 840 841 # Try to merge into master. 842 # In case a previous attempt to finish this release branch has failed, 843 # but the merge into master was successful, we skip it now 844 if ! git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH"; then 845 git_do checkout "$MASTER_BRANCH" || die "Could not check out branch '$MASTER_BRANCH'." 846 if noflag squash; then 847 git_do merge --no-ff "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now? 848 else 849 git_do merge --squash "$BRANCH" || die "There were merge conflicts." # TODO: What do we do now? 850 flag squash_info && gitflow_create_squash_message "Merged release branch '$BRANCH'" "$MASTER_BRANCH" "$BRANCH" > "$DOT_GIT_DIR/SQUASH_MSG" 851 git_do commit 852 fi 853 fi 854 855 if noflag notag; then 856 # Try to tag the release. 857 # In case a previous attempt to finish this release branch has failed, 858 # but the tag was set successful, we skip it now 859 if ! git_tag_exists "$VERSION_PREFIX$VERSION"; then 860 if [ "$FLAGS_message" != "" ] && [ "$FLAGS_messagefile" != "" ]; then 861 die "Use either -m,--message or -f,--messagefile. Can not use both options at the same time" 862 fi 863 opts="-a" 864 flag sign && opts="$opts -s" 865 [ "$FLAGS_signingkey" != "" ] && opts="$opts -u '$FLAGS_signingkey'" 866 if [ "$FLAGS_message" != "" ]; then 867 # Run filter on the tag message 868 FLAGS_message=$(run_filter_hook release-branch-tag-message "${FLAGS_message}" "$VERSION_PREFIX$VERSION") 869 opts="$opts -m '$FLAGS_message'" 870 fi 871 [ "$FLAGS_messagefile" != "" ] && opts="$opts -F '$FLAGS_messagefile'" 872 eval git_do tag $opts "$VERSION_PREFIX$VERSION" || die "Tagging failed. Please run finish again to retry." 873 fi 874 fi 875 876 run_post_hook "$VERSION_PREFIX$VERSION" "$ORIGIN" "$BRANCH" 877 878 if flag push; then 879 git_do push "$ORIGIN" "$MASTER_BRANCH" || die "Could not push branch '$MASTER_BRANCH' to remote '$ORIGIN'." 880 if noflag notag; then 881 git_do push --tags "$ORIGIN" || die "Could not push tags to remote '$ORIGIN'." 882 fi 883 fi 884 885 echo 886 echo "Summary of actions:" 887 if flag fetch; then 888 echo "- Latest objects have been fetched from '$ORIGIN'" 889 fi 890 echo "- Branch '$BRANCH' has been merged into '$MASTER_BRANCH'" 891 if noflag notag; then 892 echo "- The release was tagged '$VERSION_PREFIX$VERSION'" 893 fi 894 895 if flag push; then 896 echo "- '$MASTER_BRANCH' and tags have been pushed to '$ORIGIN'" 897 fi 898 echo "- You are now on branch '$(git_current_branch)'" 899 echo 900} 901 902cmd_publish() { 903 OPTIONS_SPEC="\ 904git flow release publish [-h] <name> 905 906Publish the release branch <name> on $ORIGIN 907-- 908h,help Show this help 909showcommands! Show git commands while executing them 910" 911 # Parse arguments 912 parse_args "$@" 913 914 # Use current branch if no version is given 915 if [ "$VERSION" = "" ]; then 916 gitflow_use_current_branch_version 917 fi 918 919 # Sanity checks 920 require_clean_working_tree 921 require_branch "$BRANCH" 922 git_do fetch -q "$ORIGIN" || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'." 923 require_branch_absent "$ORIGIN/$BRANCH" 924 925 run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH" 926 927 # Create remote branch with remote tracking 928 git_do push -u "$ORIGIN" "$BRANCH:$BRANCH" 929 git_do fetch -q "$ORIGIN" "$BRANCH" || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'." 930 git_do checkout "$BRANCH" || die "Could not check out branch '$BRANCH'." 931 932 run_post_hook "$VERSION" "$ORIGIN" "$BRANCH" 933 934 echo 935 echo "Summary of actions:" 936 echo "- The remote branch '$BRANCH' was created or updated" 937 echo "- The local branch '$BRANCH' was configured to track the remote branch" 938 echo "- You are now on branch '$(git_current_branch)'" 939 echo 940} 941 942cmd_track() { 943 OPTIONS_SPEC="\ 944git flow release track [-h] <name> 945 946Start tracking release <name> that is shared on $ORIGIN 947-- 948h,help Show this help 949showcommands! Show git commands while executing them 950" 951 # Parse arguments 952 parse_args "$@" 953 954 gitflow_require_version_arg 955 956 # Sanity checks 957 require_clean_working_tree 958 require_local_branch_absent "$BRANCH" 959 960 run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH" 961 962 git_do fetch -q "$ORIGIN" || die "Could not fetch branch '$BRANCH' from remote '$ORIGIN'." 963 git_remote_branch_exists "$ORIGIN/$BRANCH" 964 965 # Create tracking branch 966 git_do checkout -b "$BRANCH" "$ORIGIN/$BRANCH" || die "Could not create branch '$BRANCH'." 967 968 run_post_hook "$VERSION" "$ORIGIN" "$BRANCH" 969 970 echo 971 echo "Summary of actions:" 972 echo "- A new remote tracking branch '$BRANCH' was created" 973 echo "- You are now on branch '$(git_current_branch)'" 974 echo 975} 976 977cmd_rebase() { 978 OPTIONS_SPEC="\ 979git flow release rebase [-h] [-i] [-p] [<name|nameprefix>] 980 981Rebase <name> on <base_branch> 982-- 983h,help! Show this help 984showcommands! Show git commands while executing them 985i,[no]interactive Do an interactive rebase 986p,[no]preserve-merges Preserve merges 987" 988 local opts 989 990 # Define flags 991 DEFINE_boolean 'interactive' false 'do an interactive rebase' i 992 DEFINE_boolean 'preserve-merges' false 'try to recreate merges' p 993 994 # Override defaults with values from config 995 gitflow_override_flag_boolean "release.rebase.interactive" "interactive" 996 gitflow_override_flag_boolean "release.rebase.preserve-merges" "preserve_merges" 997 998 # Parse arguments 999 parse_args "$@" 1000 1001 # Use current branch if no version is given 1002 if [ "$VERSION" = "" ]; then 1003 gitflow_use_current_branch_version 1004 fi 1005 1006 BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH) 1007 BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH} 1008 1009 warn "Will try to rebase '$NAME' which is based on '$BASE_BRANCH'..." 1010 if ! git_config_bool_exists "rebase.autostash"; then 1011 require_clean_working_tree 1012 fi 1013 require_branch "$BRANCH" 1014 1015 git_local_branch_exists "$BASE_BRANCH" || die "The base '$BASE_BRANCH' doesn't exists locally or is not a branch. Can't rebase the release branch '$BRANCH'." 1016 1017 git_do checkout -q "$BRANCH" || die "Could not check out branch '$BRANCH'." 1018 if flag interactive; then 1019 opts="$opts -i" 1020 fi 1021 if flag preserve_merges; then 1022 opts="$opts -p" 1023 fi 1024 git_do rebase $opts "$BASE_BRANCH" 1025} 1026 1027cmd_delete() { 1028 OPTIONS_SPEC="\ 1029git flow release delete [-h] [-f] [-r] <name> 1030 1031Delete the given release branch 1032-- 1033h,help Show this help 1034showcommands! Show git commands while executing them 1035f,[no]force Force deletion 1036r,[no]remote Delete remote branch 1037" 1038 local current_branch 1039 1040 # Define flags 1041 DEFINE_boolean 'force' false "force deletion" f 1042 DEFINE_boolean 'remote' false "delete remote branch" r 1043 1044 # Override defaults with values from config 1045 gitflow_override_flag_boolean "release.delete.fetch" "fetch" 1046 gitflow_override_flag_boolean "release.delete.remote" "remote" 1047 1048 # Parse arguments 1049 parse_args "$@" 1050 1051 gitflow_require_version_arg 1052 1053 # Sanity checks 1054 require_branch "$BRANCH" 1055 1056 BASE_BRANCH=$(gitflow_config_get_base_branch $BRANCH) 1057 BASE_BRANCH=${BASE_BRANCH:-$DEVELOP_BRANCH} 1058 1059 run_pre_hook "$VERSION" "$ORIGIN" "$BRANCH" 1060 1061 current_branch=$(git_current_branch) 1062 # We can't delete a branch we are on, switch to the develop branch. 1063 if [ "$BRANCH" = "$current_branch" ]; then 1064 require_clean_working_tree 1065 if git_local_branch_exists "$BASE_BRANCH"; then 1066 git_do checkout "$BASE_BRANCH" 1067 else 1068 git_do checkout "$DEVELOP_BRANCH" || die "Could not check out branch '$DEVELOP_BRANCH'." 1069 fi 1070 fi 1071 1072 if ( git_is_branch_merged_into "$BRANCH" "$MASTER_BRANCH" && git_is_branch_merged_into "$BRANCH" "$BASE_BRANCH" ); then 1073 git_do branch -d "$BRANCH" || die "Could not delete the $BRANCH." 1074 if flag remote; then 1075 git_remote_branch_delete "$BRANCH" 1076 fi 1077 else 1078 if flag force; then 1079 git_do branch -D "$BRANCH" || die "Could not delete the $BRANCH." 1080 if flag remote; then 1081 git_remote_branch_delete "$BRANCH" 1082 fi 1083 else 1084 die "Release branch '$BRANCH' has been not been merged in branch '$MASTER_BRANCH' and/or branch '$BASE_BRANCH'. Use -f to force the deletion." 1085 fi 1086 fi 1087 1088 gitflow_config_remove_base_section "$BRANCH" 1089 run_post_hook "$VERSION" "$ORIGIN" "$BRANCH" 1090 1091 echo 1092 echo "Summary of actions:" 1093 echo "- Release branch '$BRANCH' has been deleted." 1094 flag remote && echo "- Release branch '$BRANCH' in '$ORIGIN' has been deleted." 1095 echo "- You are now on branch '$(git_current_branch)'" 1096 echo 1097} 1098