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