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] [<message>]] 11 or:$dashlessclear" 12 13SUBDIRECTORY_OK=Yes 14OPTIONS_SPEC= 15START_DIR=`pwd` 16. git-sh-setup 17. git-sh-i18n 18require_work_tree 19cd_to_toplevel 20 21TMP="$GIT_DIR/.git-stash.$$" 22TMPindex=${GIT_INDEX_FILE-"$GIT_DIR/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} 39 40clear_stash () { 41iftest$#!=0 42then 43 die "$(gettext "git stash clear with parameters is unimplemented")" 44fi 45if current=$(git rev-parse --verify $ref_stash 2>/dev/null) 46then 47 git update-ref -d$ref_stash $current 48fi 49} 50 51create_stash () { 52 stash_msg="$1" 53 54 git update-index -q --refresh 55if no_changes 56then 57exit0 58fi 59 60# state of the base commit 61if b_commit=$(git rev-parse --verify HEAD) 62then 63head=$(git rev-list --oneline -n 1 HEAD --) 64else 65 die "$(gettext "You do not have the initial commit yet")" 66fi 67 68if branch=$(git symbolic-ref -q HEAD) 69then 70 branch=${branch#refs/heads/} 71else 72 branch='(no branch)' 73fi 74 msg=$(printf '%s: %s' "$branch" "$head") 75 76# state of the index 77 i_tree=$(git write-tree)&& 78 i_commit=$(printf'index on %s\n'"$msg"| 79 git commit-tree$i_tree-p$b_commit) || 80 die "$(gettext "Cannot save the current index state")" 81 82iftest -z"$patch_mode" 83then 84 85# state of the working tree 86 w_tree=$( ( 87 git read-tree --index-output="$TMPindex"-m$i_tree&& 88 GIT_INDEX_FILE="$TMPindex"&& 89export GIT_INDEX_FILE && 90 git diff--name-only -z HEAD | git update-index -z --add --remove --stdin&& 91 git write-tree&& 92rm-f"$TMPindex" 93) ) || 94 die "$(gettext "Cannot save the current worktree state")" 95 96else 97 98rm-f"$TMP-index"&& 99 GIT_INDEX_FILE="$TMP-index" git read-tree HEAD && 100 101# find out what the user wants 102 GIT_INDEX_FILE="$TMP-index" \ 103 git add--interactive --patch=stash --&& 104 105# state of the working tree 106 w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree)|| 107 die "$(gettext "Cannot save the current worktree state")" 108 109 git diff-tree -p HEAD $w_tree>"$TMP-patch"&& 110test -s"$TMP-patch"|| 111 die "$(gettext "No changes selected")" 112 113rm-f"$TMP-index"|| 114 die "$(gettext "Cannot remove temporary index (can't happen)")" 115 116 fi 117 118 # create the stash 119 if test -z "$stash_msg" 120 then 121 stash_msg=$(printf 'WIP on %s' "$msg") 122 else 123 stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg") 124 fi 125 w_commit=$(printf '%s\n' "$stash_msg" | 126 git commit-tree$w_tree-p$b_commit-p$i_commit) || 127 die "$(gettext "Cannot record working tree state")" 128} 129 130save_stash () { 131 keep_index= 132 patch_mode= 133 while test$#!= 0 134 do 135 case "$1" in 136 -k|--keep-index) 137 keep_index=t 138 ;; 139 --no-keep-index) 140 keep_index=n 141 ;; 142 -p|--patch) 143 patch_mode=t 144 # only default to keep if we don't already have an override 145 test -z "$keep_index" && keep_index=t 146 ;; 147 -q|--quiet) 148 GIT_QUIET=t 149 ;; 150 --) 151 shift 152 break 153 ;; 154 -*) 155 echo "error: unknown option for'stash save':$1" 156 echo " To provide a message, use git stash save --'$1'" 157 usage 158 ;; 159 *) 160 break 161 ;; 162 esac 163 shift 164 done 165 166 stash_msg="$*" 167 168 git update-index -q --refresh 169 if no_changes 170 then 171 say "$(gettext "No local changes to save")" 172 exit 0 173 fi 174 test -f "$GIT_DIR/logs/$ref_stash" || 175 clear_stash || die "$(gettext "Cannot initialize stash")" 176 177 create_stash "$stash_msg" 178 179 # Make sure the reflog for stash is kept. 180 : >>"$GIT_DIR/logs/$ref_stash" 181 182 git update-ref -m "$stash_msg"$ref_stash$w_commit|| 183 die "$(gettext "Cannot save the current status")" 184 say Saved working directory and index state "$stash_msg" 185 186 if test -z "$patch_mode" 187 then 188 git reset --hard${GIT_QUIET:+-q} 189 190 if test "$keep_index" = "t" && test -n$i_tree 191 then 192 git read-tree --reset -u$i_tree 193 fi 194 else 195 git apply -R < "$TMP-patch" || 196 die "$(gettext "Cannot remove worktree changes")" 197 198 if test "$keep_index" != "t" 199 then 200 git reset 201 fi 202 fi 203} 204 205have_stash () { 206 git rev-parse --verify$ref_stash>/dev/null 2>&1 207} 208 209list_stash () { 210 have_stash || return 0 211 git log --format="%gd: %gs" -g "$@"$ref_stash-- 212} 213 214show_stash () { 215 assert_stash_like "$@" 216 217 git diff${FLAGS:---stat}$b_commit$w_commit 218} 219 220# 221# Parses the remaining options looking for flags and 222# at most one revision defaulting to${ref_stash}@{0} 223# if none found. 224# 225# Derives related tree and commit objects from the 226# revision, if one is found. 227# 228# stash records the work tree, and is a merge between the 229# base commit (first parent) and the index tree (second parent). 230# 231# REV is set to the symbolic version of the specified stash-like commit 232# IS_STASH_LIKE is non-blank if${REV}looks like a stash 233# IS_STASH_REF is non-blank if the${REV}looks like a stash ref 234# s is set to the SHA1 of the stash commit 235# w_commit is set to the commit containing the working tree 236# b_commit is set to the base commit 237# i_commit is set to the commit containing the index tree 238# w_tree is set to the working tree 239# b_tree is set to the base tree 240# i_tree is set to the index tree 241# 242# GIT_QUIET is set to t if -q is specified 243# INDEX_OPTION is set to --index if --index is specified. 244# FLAGS is set to the remaining flags 245# 246# dies if: 247# * too many revisions specified 248# * no revision is specified and there is no stash stack 249# * a revision is specified which cannot be resolve to a SHA1 250# * a non-existent stash reference is specified 251# 252 253parse_flags_and_rev() 254{ 255 test "$PARSE_CACHE" = "$*" && return 0 # optimisation 256 PARSE_CACHE="$*" 257 258 IS_STASH_LIKE= 259 IS_STASH_REF= 260 INDEX_OPTION= 261 s= 262 w_commit= 263 b_commit= 264 i_commit= 265 w_tree= 266 b_tree= 267 i_tree= 268 269 REV=$(git rev-parse --no-flags --symbolic "$@")|| exit 1 270 271 FLAGS= 272 for opt 273 do 274 case "$opt" in 275 -q|--quiet) 276 GIT_QUIET=-t 277 ;; 278 --index) 279 INDEX_OPTION=--index 280 ;; 281 -*) 282 FLAGS="${FLAGS}${FLAGS:+ }$opt" 283 ;; 284 esac 285 done 286 287 set --$REV 288 289 case$#in 290 0) 291 have_stash || die "$(gettext "No stash found.")" 292 set --${ref_stash}@{0} 293 ;; 294 1) 295 : 296 ;; 297 *) 298 die "$(eval_gettext "Too many revisions specified: \$REV")" 299 ;; 300 esac 301 302 REV=$(git rev-parse --quiet --symbolic --verify $1 2>/dev/null)|| { 303 reference="$1" 304 die "$(eval_gettext "\$reference is not valid reference")" 305 } 306 307 i_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null)&& 308 set --$(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null)&& 309 s=$1&& 310 w_commit=$1&& 311 b_commit=$2&& 312 w_tree=$3&& 313 b_tree=$4&& 314 i_tree=$5&& 315 IS_STASH_LIKE=t && 316 test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" && 317 IS_STASH_REF=t 318} 319 320is_stash_like() 321{ 322 parse_flags_and_rev "$@" 323 test -n "$IS_STASH_LIKE" 324} 325 326assert_stash_like() { 327 is_stash_like "$@" || { 328 args="$*" 329 die "$(eval_gettext "'\$args' is not a stash-like commit")" 330 } 331} 332 333is_stash_ref() { 334 is_stash_like "$@" && test -n "$IS_STASH_REF" 335} 336 337assert_stash_ref() { 338 is_stash_ref "$@" || { 339 args="$*" 340 die "$(eval_gettext "'\$args' is not a stash reference")" 341 } 342} 343 344apply_stash () { 345 346 assert_stash_like "$@" 347 348 git update-index -q --refresh || die "$(gettext "unable to refresh index")" 349 350 # current index state 351 c_tree=$(git write-tree)|| 352 die "$(gettext "Cannot apply a stash in the middle of a merge")" 353 354 unstashed_index_tree= 355 if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" && 356 test "$c_tree" != "$i_tree" 357 then 358 git diff-tree --binary$s^2^..$s^2 | git apply --cached 359 test $? -ne 0 && 360 die "$(gettext "Conflicts in index. Try without --index.")" 361 unstashed_index_tree=$(git write-tree)|| 362 die "$(gettext "Could not save index tree")" 363 git reset 364 fi 365 366 eval " 367 GITHEAD_$w_tree='Stashed changes'&& 368 GITHEAD_$c_tree='Updated upstream'&& 369 GITHEAD_$b_tree='Version stash was based on'&& 370export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree 371" 372 373 if test -n "$GIT_QUIET" 374 then 375 GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY 376 fi 377 if git merge-recursive$b_tree--$c_tree$w_tree 378 then 379 # No conflict 380 if test -n "$unstashed_index_tree" 381 then 382 git read-tree "$unstashed_index_tree" 383 else 384 a="$TMP-added" && 385 git diff-index --cached --name-only --diff-filter=A$c_tree>"$a" && 386 git read-tree --reset$c_tree&& 387 git update-index --add --stdin <"$a" || 388 die "$(gettext "Cannot unstage modified files")" 389 rm -f "$a" 390 fi 391 squelch= 392 if test -n "$GIT_QUIET" 393 then 394 squelch='>/dev/null 2>&1' 395 fi 396 (cd "$START_DIR" && eval "git status $squelch") || : 397 else 398 # Merge conflict; keep the exit status from merge-recursive 399 status=$? 400 if test -n "$INDEX_OPTION" 401 then 402 ( 403 gettext "Index was not unstashed." && 404 echo 405 ) >&2 406 fi 407 exit$status 408 fi 409} 410 411pop_stash() { 412 assert_stash_ref "$@" 413 414 apply_stash "$@" && 415 drop_stash "$@" 416} 417 418drop_stash () { 419 assert_stash_ref "$@" 420 421 git reflog delete --updateref --rewrite "${REV}" && 422 say "Dropped ${REV}($s)" || die "${REV}: Could not drop stash entry" 423 424 # clear_stash if we just dropped the last stash entry 425 git rev-parse --verify "$ref_stash@{0}" > /dev/null 2>&1 || clear_stash 426} 427 428apply_to_branch () { 429 test -n "$1" || die "$(gettext "No branch name specified")" 430 branch=$1 431 shift 1 432 433 set -- --index "$@" 434 assert_stash_like "$@" 435 436 git checkout -b$branch$REV^ && 437 apply_stash "$@" && { 438 test -z "$IS_STASH_REF" || drop_stash "$@" 439 } 440} 441 442PARSE_CACHE='--not-parsed' 443# The default command is "save" if nothing but options are given 444seen_non_option= 445for opt 446do 447 case "$opt" in 448 -*) ;; 449 *) seen_non_option=t; break ;; 450 esac 451done 452 453test -n "$seen_non_option" || set "save" "$@" 454 455# Main command set 456case "$1" in 457list) 458 shift 459 list_stash "$@" 460 ;; 461show) 462 shift 463 show_stash "$@" 464 ;; 465save) 466 shift 467 save_stash "$@" 468 ;; 469apply) 470 shift 471 apply_stash "$@" 472 ;; 473clear) 474 shift 475 clear_stash "$@" 476 ;; 477create) 478 if test$#-gt 0 && test "$1" = create 479 then 480 shift 481 fi 482 create_stash "$*" && echo "$w_commit" 483 ;; 484drop) 485 shift 486 drop_stash "$@" 487 ;; 488pop) 489 shift 490 pop_stash "$@" 491 ;; 492branch) 493 shift 494 apply_to_branch "$@" 495 ;; 496*) 497 case$#in 498 0) 499 save_stash && 500 say "$(gettext "(To restore them type \"git stash apply\")")" 501;; 502*) 503 usage 504esac 505;; 506esac