1#!/bin/sh 2# Copyright (c) 2007, Nanako Shiraishi 3 4dashless=$(basename "$0" | sed -e 's/-/ /') 5USAGE="list [<options>] 6 or:$dashlessshow [<stash>] 7 or:$dashlessdrop [-q|--quiet] [<stash>] 8 or:$dashless( pop | apply ) [--index] [-q|--quiet] [<stash>] 9 or:$dashlessbranch <branchname> [<stash>] 10 or:$dashless[save [--patch] [-k|--[no-]keep-index] [-q|--quiet] 11 [-u|--include-untracked] [-a|--all] [<message>]] 12 or:$dashlesspush [--patch] [-k|--[no-]keep-index] [-q|--quiet] 13 [-u|--include-untracked] [-a|--all] [-m <message>] 14 or:$dashlessclear" 15 16SUBDIRECTORY_OK=Yes 17OPTIONS_SPEC= 18START_DIR=$(pwd) 19. git-sh-setup 20require_work_tree 21cd_to_toplevel 22 23TMP="$GIT_DIR/.git-stash.$$" 24TMPindex=${GIT_INDEX_FILE-"$(git rev-parse --git-path index)"}.stash.$$ 25trap'rm -f "$TMP-"* "$TMPindex"'0 26 27ref_stash=refs/stash 28 29if git config --get-colorbool color.interactive;then 30 help_color="$(git config --get-color color.interactive.help 'red bold')" 31 reset_color="$(git config --get-color '' reset)" 32else 33 help_color= 34 reset_color= 35fi 36 37no_changes () { 38 git diff-index --quiet --cached HEAD --ignore-submodules --&& 39 git diff-files --quiet --ignore-submodules&& 40(test -z"$untracked"||test -z"$(untracked_files)") 41} 42 43untracked_files () { 44 excl_opt=--exclude-standard 45test"$untracked"="all"&& excl_opt= 46 git ls-files -o -z$excl_opt 47} 48 49clear_stash () { 50iftest$#!=0 51then 52 die "$(gettext "git stash clear with parameters is unimplemented")" 53fi 54if current=$(git rev-parse --verify --quiet $ref_stash) 55then 56 git update-ref -d$ref_stash $current 57fi 58} 59 60create_stash () { 61 stash_msg="$1" 62 untracked="$2" 63 64 git update-index -q --refresh 65if no_changes 66then 67exit0 68fi 69 70# state of the base commit 71if b_commit=$(git rev-parse --verify HEAD) 72then 73head=$(git rev-list --oneline -n 1 HEAD --) 74else 75 die "$(gettext "You do not have the initial commit yet")" 76fi 77 78if branch=$(git symbolic-ref -q HEAD) 79then 80 branch=${branch#refs/heads/} 81else 82 branch='(no branch)' 83fi 84 msg=$(printf '%s: %s' "$branch" "$head") 85 86# state of the index 87 i_tree=$(git write-tree)&& 88 i_commit=$(printf'index on %s\n'"$msg"| 89 git commit-tree$i_tree-p$b_commit) || 90 die "$(gettext "Cannot save the current index state")" 91 92iftest -n"$untracked" 93then 94# Untracked files are stored by themselves in a parentless commit, for 95# ease of unpacking later. 96 u_commit=$( 97 untracked_files | ( 98 GIT_INDEX_FILE="$TMPindex"&& 99export GIT_INDEX_FILE && 100rm-f"$TMPindex"&& 101 git update-index -z --add --remove --stdin&& 102 u_tree=$(git write-tree)&& 103printf'untracked files on %s\n'"$msg"| git commit-tree$u_tree&& 104rm-f"$TMPindex" 105) ) || die "$(gettext "Cannot save the untracked files")" 106 107 untracked_commit_option="-p$u_commit"; 108else 109 untracked_commit_option= 110fi 111 112iftest -z"$patch_mode" 113then 114 115# state of the working tree 116 w_tree=$( ( 117 git read-tree --index-output="$TMPindex"-m$i_tree&& 118 GIT_INDEX_FILE="$TMPindex"&& 119export GIT_INDEX_FILE && 120 git diff-index --name-only -z HEAD -->"$TMP-stagenames"&& 121 git update-index -z --add --remove --stdin<"$TMP-stagenames"&& 122 git write-tree&& 123rm-f"$TMPindex" 124) ) || 125 die "$(gettext "Cannot save the current worktree state")" 126 127else 128 129rm-f"$TMP-index"&& 130 GIT_INDEX_FILE="$TMP-index" git read-tree HEAD && 131 132# find out what the user wants 133 GIT_INDEX_FILE="$TMP-index" \ 134 git add--interactive --patch=stash --&& 135 136# state of the working tree 137 w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree)|| 138 die "$(gettext "Cannot save the current worktree state")" 139 140 git diff-tree -p HEAD $w_tree-->"$TMP-patch"&& 141test -s"$TMP-patch"|| 142 die "$(gettext "No changes selected")" 143 144rm-f"$TMP-index"|| 145 die "$(gettext "Cannot remove temporary index (can't happen)")" 146 147 fi 148 149 # create the stash 150 if test -z "$stash_msg" 151 then 152 stash_msg=$(printf 'WIP on %s' "$msg") 153 else 154 stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg") 155 fi 156 w_commit=$(printf '%s\n' "$stash_msg" | 157 git commit-tree$w_tree-p$b_commit-p$i_commit$untracked_commit_option) || 158 die "$(gettext "Cannot record working tree state")" 159} 160 161store_stash () { 162 while test$#!= 0 163 do 164 case "$1" in 165 -m|--message) 166 shift 167 stash_msg="$1" 168 ;; 169 -q|--quiet) 170 quiet=t 171 ;; 172 *) 173 break 174 ;; 175 esac 176 shift 177 done 178 test$#= 1 || 179 die "$(eval_gettext "\"$dashless store\" requires one <commit> argument")" 180 181 w_commit="$1" 182 if test -z "$stash_msg" 183 then 184 stash_msg="Created via \"git stash store\"." 185 fi 186 187 git update-ref --create-reflog -m "$stash_msg"$ref_stash$w_commit 188 ret=$? 189 test$ret!= 0 && test -z "$quiet" && 190 die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")" 191 return$ret 192} 193 194push_stash () { 195 keep_index= 196 patch_mode= 197 untracked= 198 stash_msg= 199 while test$#!= 0 200 do 201 case "$1" in 202 -k|--keep-index) 203 keep_index=t 204 ;; 205 --no-keep-index) 206 keep_index=n 207 ;; 208 -p|--patch) 209 patch_mode=t 210 # only default to keep if we don't already have an override 211 test -z "$keep_index" && keep_index=t 212 ;; 213 -q|--quiet) 214 GIT_QUIET=t 215 ;; 216 -u|--include-untracked) 217 untracked=untracked 218 ;; 219 -a|--all) 220 untracked=all 221 ;; 222 -m|--message) 223 shift 224 test -z${1+x}&& usage 225 stash_msg=$1 226 ;; 227 --help) 228 show_help 229 ;; 230 --) 231 shift 232 break 233 ;; 234 -*) 235 option="$1" 236 # TRANSLATORS:$optionis an invalid option, like 237 # `--blah-blah'. The 7 spaces at the beginning of the 238 # second line correspond to "error:". So you should line 239 # up the second line with however many characters the 240 # translation of "error:" takes in your language. E.g. in 241 # English this is: 242 # 243 # $ git stash save --blah-blah 2>&1 | head -n 2 244 # error: unknown option for 'stash save': --blah-blah 245 # To provide a message, use git stash save -- '--blah-blah' 246 eval_gettextln "error: unknown option for'stash save': \$option 247 To provide a message, use git stash save --'\$option'" 248 usage 249 ;; 250 *) 251 break 252 ;; 253 esac 254 shift 255 done 256 257 if test -n "$patch_mode" && test -n "$untracked" 258 then 259 die "$(gettext "Can't use --patch and --include-untracked or --all at the same time")" 260 fi 261 262 git update-index -q --refresh 263 if no_changes 264 then 265 say "$(gettext "No local changes to save")" 266 exit 0 267 fi 268 git reflog exists$ref_stash|| 269 clear_stash || die "$(gettext "Cannot initialize stash")" 270 271 create_stash "$stash_msg"$untracked 272 store_stash -m "$stash_msg" -q$w_commit|| 273 die "$(gettext "Cannot save the current status")" 274 say "$(eval_gettext "Saved working directory and index state \$stash_msg")" 275 276 if test -z "$patch_mode" 277 then 278 git reset --hard${GIT_QUIET:+-q} 279 test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION= 280 if test -n "$untracked" 281 then 282 git clean --force --quiet -d$CLEAN_X_OPTION 283 fi 284 285 if test "$keep_index" = "t" && test -n "$i_tree" 286 then 287 git read-tree --reset -u$i_tree 288 fi 289 else 290 git apply -R < "$TMP-patch" || 291 die "$(gettext "Cannot remove worktree changes")" 292 293 if test "$keep_index" != "t" 294 then 295 git reset 296 fi 297 fi 298} 299 300save_stash () { 301 push_options= 302 while test$#!= 0 303 do 304 case "$1" in 305 --) 306 shift 307 break 308 ;; 309 -*) 310 # pass all options through to push_stash 311 push_options="$push_options $1" 312 ;; 313 *) 314 break 315 ;; 316 esac 317 shift 318 done 319 320 stash_msg="$*" 321 322 if test -z "$stash_msg" 323 then 324 push_stash$push_options 325 else 326 push_stash$push_options-m "$stash_msg" 327 fi 328} 329 330have_stash () { 331 git rev-parse --verify --quiet$ref_stash>/dev/null 332} 333 334list_stash () { 335 have_stash || return 0 336 git log --format="%gd: %gs" -g --first-parent -m "$@"$ref_stash-- 337} 338 339show_stash () { 340 ALLOW_UNKNOWN_FLAGS=t 341 assert_stash_like "$@" 342 343 if test -z "$FLAGS" 344 then 345 if test "$(git config --bool stash.showStat || echo true)" = "true" 346 then 347 FLAGS=--stat 348 fi 349 350 if test "$(git config --bool stash.showPatch || echo false)" = "true" 351 then 352 FLAGS=${FLAGS}${FLAGS:+ }-p 353 fi 354 355 if test -z "$FLAGS" 356 then 357 return 0 358 fi 359 fi 360 361 git diff${FLAGS}$b_commit$w_commit 362} 363 364show_help () { 365 exec git help stash 366 exit 1 367} 368 369# 370# Parses the remaining options looking for flags and 371# at most one revision defaulting to${ref_stash}@{0} 372# if none found. 373# 374# Derives related tree and commit objects from the 375# revision, if one is found. 376# 377# stash records the work tree, and is a merge between the 378# base commit (first parent) and the index tree (second parent). 379# 380# REV is set to the symbolic version of the specified stash-like commit 381# IS_STASH_LIKE is non-blank if${REV}looks like a stash 382# IS_STASH_REF is non-blank if the${REV}looks like a stash ref 383# s is set to the SHA1 of the stash commit 384# w_commit is set to the commit containing the working tree 385# b_commit is set to the base commit 386# i_commit is set to the commit containing the index tree 387# u_commit is set to the commit containing the untracked files tree 388# w_tree is set to the working tree 389# b_tree is set to the base tree 390# i_tree is set to the index tree 391# u_tree is set to the untracked files tree 392# 393# GIT_QUIET is set to t if -q is specified 394# INDEX_OPTION is set to --index if --index is specified. 395# FLAGS is set to the remaining flags (if allowed) 396# 397# dies if: 398# * too many revisions specified 399# * no revision is specified and there is no stash stack 400# * a revision is specified which cannot be resolve to a SHA1 401# * a non-existent stash reference is specified 402# * unknown flags were set and ALLOW_UNKNOWN_FLAGS is not "t" 403# 404 405parse_flags_and_rev() 406{ 407 test "$PARSE_CACHE" = "$*" && return 0 # optimisation 408 PARSE_CACHE="$*" 409 410 IS_STASH_LIKE= 411 IS_STASH_REF= 412 INDEX_OPTION= 413 s= 414 w_commit= 415 b_commit= 416 i_commit= 417 u_commit= 418 w_tree= 419 b_tree= 420 i_tree= 421 u_tree= 422 423 FLAGS= 424 REV= 425 for opt 426 do 427 case "$opt" in 428 -q|--quiet) 429 GIT_QUIET=-t 430 ;; 431 --index) 432 INDEX_OPTION=--index 433 ;; 434 --help) 435 show_help 436 ;; 437 -*) 438 test "$ALLOW_UNKNOWN_FLAGS" = t || 439 die "$(eval_gettext "unknown option: \$opt")" 440 FLAGS="${FLAGS}${FLAGS:+ }$opt" 441 ;; 442 *) 443 REV="${REV}${REV:+ }'$opt'" 444 ;; 445 esac 446 done 447 448 eval set --$REV 449 450 case$#in 451 0) 452 have_stash || die "$(gettext "No stash found.")" 453 set --${ref_stash}@{0} 454 ;; 455 1) 456 : 457 ;; 458 *) 459 die "$(eval_gettext "Too many revisions specified: \$REV")" 460 ;; 461 esac 462 463 case "$1" in 464 *[!0-9]*) 465 : 466 ;; 467 *) 468 set -- "${ref_stash}@{$1}" 469 ;; 470 esac 471 472 REV=$(git rev-parse --symbolic --verify --quiet "$1")|| { 473 reference="$1" 474 die "$(eval_gettext "\$reference is not a valid reference")" 475 } 476 477 i_commit=$(git rev-parse --verify --quiet "$REV^2")&& 478 set --$(git rev-parse "$REV" "$REV^1" "$REV:" "$REV^1:" "$REV^2:" 2>/dev/null)&& 479 s=$1&& 480 w_commit=$1&& 481 b_commit=$2&& 482 w_tree=$3&& 483 b_tree=$4&& 484 i_tree=$5&& 485 IS_STASH_LIKE=t && 486 test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" && 487 IS_STASH_REF=t 488 489 u_commit=$(git rev-parse --verify --quiet "$REV^3")&& 490 u_tree=$(git rev-parse "$REV^3:" 2>/dev/null) 491} 492 493is_stash_like() 494{ 495 parse_flags_and_rev "$@" 496 test -n "$IS_STASH_LIKE" 497} 498 499assert_stash_like() { 500 is_stash_like "$@" || { 501 args="$*" 502 die "$(eval_gettext "'\$args' is not a stash-like commit")" 503 } 504} 505 506is_stash_ref() { 507 is_stash_like "$@" && test -n "$IS_STASH_REF" 508} 509 510assert_stash_ref() { 511 is_stash_ref "$@" || { 512 args="$*" 513 die "$(eval_gettext "'\$args' is not a stash reference")" 514 } 515} 516 517apply_stash () { 518 519 assert_stash_like "$@" 520 521 git update-index -q --refresh || die "$(gettext "unable to refresh index")" 522 523 # current index state 524 c_tree=$(git write-tree)|| 525 die "$(gettext "Cannot apply a stash in the middle of a merge")" 526 527 unstashed_index_tree= 528 if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" && 529 test "$c_tree" != "$i_tree" 530 then 531 git diff-tree --binary$s^2^..$s^2 | git apply --cached 532 test $? -ne 0 && 533 die "$(gettext "Conflicts in index. Try without --index.")" 534 unstashed_index_tree=$(git write-tree)|| 535 die "$(gettext "Could not save index tree")" 536 git reset 537 fi 538 539 if test -n "$u_tree" 540 then 541 GIT_INDEX_FILE="$TMPindex" git-read-tree "$u_tree" && 542 GIT_INDEX_FILE="$TMPindex" git checkout-index --all && 543 rm -f "$TMPindex" || 544 die "$(gettext "Could not restore untracked files from stash")" 545 fi 546 547 eval " 548 GITHEAD_$w_tree='Stashed changes'&& 549 GITHEAD_$c_tree='Updated upstream'&& 550 GITHEAD_$b_tree='Version stash was based on'&& 551export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree 552" 553 554 if test -n "$GIT_QUIET" 555 then 556 GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY 557 fi 558 if git merge-recursive$b_tree--$c_tree$w_tree 559 then 560 # No conflict 561 if test -n "$unstashed_index_tree" 562 then 563 git read-tree "$unstashed_index_tree" 564 else 565 a="$TMP-added" && 566 git diff-index --cached --name-only --diff-filter=A$c_tree>"$a" && 567 git read-tree --reset$c_tree&& 568 git update-index --add --stdin <"$a" || 569 die "$(gettext "Cannot unstage modified files")" 570 rm -f "$a" 571 fi 572 squelch= 573 if test -n "$GIT_QUIET" 574 then 575 squelch='>/dev/null 2>&1' 576 fi 577 (cd "$START_DIR" && eval "git status $squelch") || : 578 else 579 # Merge conflict; keep the exit status from merge-recursive 580 status=$? 581 git rerere 582 if test -n "$INDEX_OPTION" 583 then 584 gettextln "Index was not unstashed." >&2 585 fi 586 exit$status 587 fi 588} 589 590pop_stash() { 591 assert_stash_ref "$@" 592 593 if apply_stash "$@" 594 then 595 drop_stash "$@" 596 else 597 status=$? 598 say "$(gettext "The stash is kept in case you need it again.")" 599 exit$status 600 fi 601} 602 603drop_stash () { 604 assert_stash_ref "$@" 605 606 git reflog delete --updateref --rewrite "${REV}" && 607 say "$(eval_gettext "Dropped \${REV} (\$s)")"|| 608 die "$(eval_gettext "\${REV}: Could not drop stash entry")" 609 610# clear_stash if we just dropped the last stash entry 611 git rev-parse --verify --quiet"$ref_stash@{0}">/dev/null || 612 clear_stash 613} 614 615apply_to_branch () { 616test -n"$1"|| die "$(gettext "No branch name specified")" 617 branch=$1 618shift1 619 620set -- --index"$@" 621 assert_stash_like "$@" 622 623 git checkout -b$branch $REV^ && 624 apply_stash "$@"&& { 625test -z"$IS_STASH_REF"|| drop_stash "$@" 626} 627} 628 629PARSE_CACHE='--not-parsed' 630# The default command is "save" if nothing but options are given 631seen_non_option= 632for opt 633do 634case"$opt"in 635-*) ;; 636*) seen_non_option=t;break;; 637esac 638done 639 640test -n"$seen_non_option"||set"save""$@" 641 642# Main command set 643case"$1"in 644list) 645shift 646 list_stash "$@" 647;; 648show) 649shift 650 show_stash "$@" 651;; 652save) 653shift 654 save_stash "$@" 655;; 656push) 657shift 658 push_stash "$@" 659;; 660apply) 661shift 662 apply_stash "$@" 663;; 664clear) 665shift 666 clear_stash "$@" 667;; 668create) 669shift 670 create_stash "$*"&&echo"$w_commit" 671;; 672store) 673shift 674 store_stash "$@" 675;; 676drop) 677shift 678 drop_stash "$@" 679;; 680pop) 681shift 682 pop_stash "$@" 683;; 684branch) 685shift 686 apply_to_branch "$@" 687;; 688*) 689case$#in 6900) 691 save_stash && 692 say "$(gettext "(To restore them type \"git stash apply\")")" 693 ;; 694 *) 695 usage 696 esac 697 ;; 698esac