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 18. git-sh-i18n 19require_work_tree 20cd_to_toplevel 21 22TMP="$GIT_DIR/.git-stash.$$" 23TMPindex=${GIT_INDEX_FILE-"$GIT_DIR/index"}.stash.$$ 24trap'rm -f "$TMP-"* "$TMPindex"'0 25 26ref_stash=refs/stash 27 28if git config --get-colorbool color.interactive;then 29 help_color="$(git config --get-color color.interactive.help 'red bold')" 30 reset_color="$(git config --get-color '' reset)" 31else 32 help_color= 33 reset_color= 34fi 35 36no_changes () { 37 git diff-index --quiet --cached HEAD --ignore-submodules --&& 38 git diff-files --quiet --ignore-submodules&& 39(test -z"$untracked"||test -z"$(untracked_files)") 40} 41 42untracked_files () { 43 excl_opt=--exclude-standard 44test"$untracked"="all"&& excl_opt= 45 git ls-files -o -z$excl_opt 46} 47 48clear_stash () { 49iftest$#!=0 50then 51 die "$(gettext "git stash clear with parameters is unimplemented")" 52fi 53if current=$(git rev-parse --verify $ref_stash 2>/dev/null) 54then 55 git update-ref -d$ref_stash $current 56fi 57} 58 59create_stash () { 60 stash_msg="$1" 61 untracked="$2" 62 63 git update-index -q --refresh 64if no_changes 65then 66exit0 67fi 68 69# state of the base commit 70if b_commit=$(git rev-parse --verify HEAD) 71then 72head=$(git rev-list --oneline -n 1 HEAD --) 73else 74 die "$(gettext "You do not have the initial commit yet")" 75fi 76 77if branch=$(git symbolic-ref -q HEAD) 78then 79 branch=${branch#refs/heads/} 80else 81 branch='(no branch)' 82fi 83 msg=$(printf '%s: %s' "$branch" "$head") 84 85# state of the index 86 i_tree=$(git write-tree)&& 87 i_commit=$(printf'index on %s\n'"$msg"| 88 git commit-tree$i_tree-p$b_commit) || 89 die "$(gettext "Cannot save the current index state")" 90 91iftest -n"$untracked" 92then 93# Untracked files are stored by themselves in a parentless commit, for 94# ease of unpacking later. 95 u_commit=$( 96 untracked_files | ( 97export GIT_INDEX_FILE="$TMPindex" 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 "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 # Make sure the reflog for stash is kept. 186 : >>"$GIT_DIR/logs/$ref_stash" 187 git update-ref -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 194save_stash () { 195 keep_index= 196 patch_mode= 197 untracked= 198 force= 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 -f|--force) 220 force=t 221 ;; 222 -a|--all) 223 untracked=all 224 ;; 225 --) 226 shift 227 break 228 ;; 229 -*) 230 option="$1" 231 # TRANSLATORS:$optionis an invalid option, like 232 # `--blah-blah'. The 7 spaces at the beginning of the 233 # second line correspond to "error:". So you should line 234 # up the second line with however many characters the 235 # translation of "error:" takes in your language. E.g. in 236 # English this is: 237 # 238 # $ git stash save --blah-blah 2>&1 | head -n 2 239 # error: unknown option for 'stash save': --blah-blah 240 # To provide a message, use git stash save -- '--blah-blah' 241 eval_gettextln "error: unknown option for'stash save': \$option 242 To provide a message, use git stash save --'\$option'" 243 usage 244 ;; 245 *) 246 break 247 ;; 248 esac 249 shift 250 done 251 252 if test -n "$patch_mode" && test -n "$untracked" 253 then 254 die "Can't use --patch and --include-untracked or --all at the same time" 255 fi 256 257 stash_msg="$*" 258 259 git update-index -q --refresh 260 if no_changes 261 then 262 say "$(gettext "No local changes to save")" 263 exit 0 264 fi 265 if test -z "$untracked$force" && 266 test -n "$(git ls-files --killed | head -n 1)" 267 then 268 say "$(gettext "The following untracked files would NOT be saved but need to be removed by stash save:")" 269 test -n "$GIT_QUIET" || git ls-files --killed | sed 's/^/\t/' 270 say "$(gettext "Aborting. Consider using either the --force or --include-untracked option.")" >&2 271 exit 1 272 fi 273 test -f "$GIT_DIR/logs/$ref_stash" || 274 clear_stash || die "$(gettext "Cannot initialize stash")" 275 276 create_stash "$stash_msg"$untracked 277 store_stash -m "$stash_msg" -q$w_commit|| 278 die "$(gettext "Cannot save the current status")" 279 say Saved working directory and index state "$stash_msg" 280 281 if test -z "$patch_mode" 282 then 283 git reset --hard${GIT_QUIET:+-q} 284 test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION= 285 if test -n "$untracked" 286 then 287 git clean --force --quiet -d$CLEAN_X_OPTION 288 fi 289 290 if test "$keep_index" = "t" && test -n$i_tree 291 then 292 git read-tree --reset -u$i_tree 293 fi 294 else 295 git apply -R < "$TMP-patch" || 296 die "$(gettext "Cannot remove worktree changes")" 297 298 if test "$keep_index" != "t" 299 then 300 git reset 301 fi 302 fi 303} 304 305have_stash () { 306 git rev-parse --verify$ref_stash>/dev/null 2>&1 307} 308 309list_stash () { 310 have_stash || return 0 311 git log --format="%gd: %gs" -g "$@"$ref_stash-- 312} 313 314show_stash () { 315 assert_stash_like "$@" 316 317 git diff${FLAGS:---stat}$b_commit$w_commit 318} 319 320# 321# Parses the remaining options looking for flags and 322# at most one revision defaulting to${ref_stash}@{0} 323# if none found. 324# 325# Derives related tree and commit objects from the 326# revision, if one is found. 327# 328# stash records the work tree, and is a merge between the 329# base commit (first parent) and the index tree (second parent). 330# 331# REV is set to the symbolic version of the specified stash-like commit 332# IS_STASH_LIKE is non-blank if${REV}looks like a stash 333# IS_STASH_REF is non-blank if the${REV}looks like a stash ref 334# s is set to the SHA1 of the stash commit 335# w_commit is set to the commit containing the working tree 336# b_commit is set to the base commit 337# i_commit is set to the commit containing the index tree 338# u_commit is set to the commit containing the untracked files tree 339# w_tree is set to the working tree 340# b_tree is set to the base tree 341# i_tree is set to the index tree 342# u_tree is set to the untracked files tree 343# 344# GIT_QUIET is set to t if -q is specified 345# INDEX_OPTION is set to --index if --index is specified. 346# FLAGS is set to the remaining flags 347# 348# dies if: 349# * too many revisions specified 350# * no revision is specified and there is no stash stack 351# * a revision is specified which cannot be resolve to a SHA1 352# * a non-existent stash reference is specified 353# 354 355parse_flags_and_rev() 356{ 357 test "$PARSE_CACHE" = "$*" && return 0 # optimisation 358 PARSE_CACHE="$*" 359 360 IS_STASH_LIKE= 361 IS_STASH_REF= 362 INDEX_OPTION= 363 s= 364 w_commit= 365 b_commit= 366 i_commit= 367 u_commit= 368 w_tree= 369 b_tree= 370 i_tree= 371 u_tree= 372 373 REV=$(git rev-parse --no-flags --symbolic "$@")|| exit 1 374 375 FLAGS= 376 for opt 377 do 378 case "$opt" in 379 -q|--quiet) 380 GIT_QUIET=-t 381 ;; 382 --index) 383 INDEX_OPTION=--index 384 ;; 385 -*) 386 FLAGS="${FLAGS}${FLAGS:+ }$opt" 387 ;; 388 esac 389 done 390 391 set --$REV 392 393 case$#in 394 0) 395 have_stash || die "$(gettext "No stash found.")" 396 set --${ref_stash}@{0} 397 ;; 398 1) 399 : 400 ;; 401 *) 402 die "$(eval_gettext "Too many revisions specified: \$REV")" 403 ;; 404 esac 405 406 REV=$(git rev-parse --quiet --symbolic --verify $1 2>/dev/null)|| { 407 reference="$1" 408 die "$(eval_gettext "\$reference is not valid reference")" 409 } 410 411 i_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null)&& 412 set --$(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null)&& 413 s=$1&& 414 w_commit=$1&& 415 b_commit=$2&& 416 w_tree=$3&& 417 b_tree=$4&& 418 i_tree=$5&& 419 IS_STASH_LIKE=t && 420 test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" && 421 IS_STASH_REF=t 422 423 u_commit=$(git rev-parse --quiet --verify $REV^3 2>/dev/null)&& 424 u_tree=$(git rev-parse $REV^3: 2>/dev/null) 425} 426 427is_stash_like() 428{ 429 parse_flags_and_rev "$@" 430 test -n "$IS_STASH_LIKE" 431} 432 433assert_stash_like() { 434 is_stash_like "$@" || { 435 args="$*" 436 die "$(eval_gettext "'\$args' is not a stash-like commit")" 437 } 438} 439 440is_stash_ref() { 441 is_stash_like "$@" && test -n "$IS_STASH_REF" 442} 443 444assert_stash_ref() { 445 is_stash_ref "$@" || { 446 args="$*" 447 die "$(eval_gettext "'\$args' is not a stash reference")" 448 } 449} 450 451apply_stash () { 452 453 assert_stash_like "$@" 454 455 git update-index -q --refresh || die "$(gettext "unable to refresh index")" 456 457 # current index state 458 c_tree=$(git write-tree)|| 459 die "$(gettext "Cannot apply a stash in the middle of a merge")" 460 461 unstashed_index_tree= 462 if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" && 463 test "$c_tree" != "$i_tree" 464 then 465 git diff-tree --binary$s^2^..$s^2 | git apply --cached 466 test $? -ne 0 && 467 die "$(gettext "Conflicts in index. Try without --index.")" 468 unstashed_index_tree=$(git write-tree)|| 469 die "$(gettext "Could not save index tree")" 470 git reset 471 fi 472 473 if test -n "$u_tree" 474 then 475 GIT_INDEX_FILE="$TMPindex" git-read-tree "$u_tree" && 476 GIT_INDEX_FILE="$TMPindex" git checkout-index --all && 477 rm -f "$TMPindex" || 478 die 'Could not restore untracked files from stash' 479 fi 480 481 eval " 482 GITHEAD_$w_tree='Stashed changes' && 483 GITHEAD_$c_tree='Updated upstream' && 484 GITHEAD_$b_tree='Version stash was based on' && 485 export GITHEAD_$w_treeGITHEAD_$c_treeGITHEAD_$b_tree 486 " 487 488 if test -n "$GIT_QUIET" 489 then 490 GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY 491 fi 492 if git merge-recursive$b_tree--$c_tree$w_tree 493 then 494 # No conflict 495 if test -n "$unstashed_index_tree" 496 then 497 git read-tree "$unstashed_index_tree" 498 else 499 a="$TMP-added" && 500 git diff-index --cached --name-only --diff-filter=A$c_tree>"$a" && 501 git read-tree --reset$c_tree&& 502 git update-index --add --stdin <"$a" || 503 die "$(gettext "Cannot unstage modified files")" 504 rm -f "$a" 505 fi 506 squelch= 507 if test -n "$GIT_QUIET" 508 then 509 squelch='>/dev/null 2>&1' 510 fi 511 (cd "$START_DIR" && eval "git status$squelch") || : 512 else 513 # Merge conflict; keep the exit status from merge-recursive 514 status=$? 515 git rerere 516 if test -n "$INDEX_OPTION" 517 then 518 gettextln "Index was not unstashed." >&2 519 fi 520 exit$status 521 fi 522} 523 524pop_stash() { 525 assert_stash_ref "$@" 526 527 apply_stash "$@" && 528 drop_stash "$@" 529} 530 531drop_stash () { 532 assert_stash_ref "$@" 533 534 git reflog delete --updateref --rewrite "${REV}" && 535 say "$(eval_gettext "Dropped \${REV} (\$s)")" || 536 die "$(eval_gettext "\${REV}: Could not drop stash entry")" 537 538 # clear_stash if we just dropped the last stash entry 539 git rev-parse --verify "$ref_stash@{0}" >/dev/null 2>&1 || clear_stash 540} 541 542apply_to_branch () { 543 test -n "$1" || die "$(gettext "No branch name specified")" 544 branch=$1 545 shift 1 546 547 set -- --index "$@" 548 assert_stash_like "$@" 549 550 git checkout -b$branch$REV^ && 551 apply_stash "$@" && { 552 test -z "$IS_STASH_REF" || drop_stash "$@" 553 } 554} 555 556PARSE_CACHE='--not-parsed' 557# The default command is "save" if nothing but options are given 558seen_non_option= 559for opt 560do 561 case "$opt" in 562 -*) ;; 563 *) seen_non_option=t; break ;; 564 esac 565done 566 567test -n "$seen_non_option" || set "save" "$@" 568 569# Main command set 570case "$1" in 571list) 572 shift 573 list_stash "$@" 574 ;; 575show) 576 shift 577 show_stash "$@" 578 ;; 579save) 580 shift 581 save_stash "$@" 582 ;; 583apply) 584 shift 585 apply_stash "$@" 586 ;; 587clear) 588 shift 589 clear_stash "$@" 590 ;; 591create) 592 shift 593 create_stash "$*" && echo "$w_commit" 594 ;; 595store) 596 shift 597 store_stash "$@" 598 ;; 599drop) 600 shift 601 drop_stash "$@" 602 ;; 603pop) 604 shift 605 pop_stash "$@" 606 ;; 607branch) 608 shift 609 apply_to_branch "$@" 610 ;; 611*) 612 case$#in 613 0) 614 save_stash && 615 say "$(gettext "(To restore them type \"git stash apply\")")" 616 ;; 617 *) 618 usage 619 esac 620 ;; 621esac