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)|| die "$1 is not valid reference" 303 304 i_commit=$(git rev-parse --quiet --verify $REV^2 2>/dev/null)&& 305 set --$(git rev-parse $REV $REV^1 $REV: $REV^1: $REV^2: 2>/dev/null)&& 306 s=$1&& 307 w_commit=$1&& 308 b_commit=$2&& 309 w_tree=$3&& 310 b_tree=$4&& 311 i_tree=$5&& 312 IS_STASH_LIKE=t && 313 test "$ref_stash" = "$(git rev-parse --symbolic-full-name "${REV%@*}")" && 314 IS_STASH_REF=t 315} 316 317is_stash_like() 318{ 319 parse_flags_and_rev "$@" 320 test -n "$IS_STASH_LIKE" 321} 322 323assert_stash_like() { 324 is_stash_like "$@" || { 325 args="$*" 326 die "$(eval_gettext "'\$args' is not a stash-like commit")" 327 } 328} 329 330is_stash_ref() { 331 is_stash_like "$@" && test -n "$IS_STASH_REF" 332} 333 334assert_stash_ref() { 335 is_stash_ref "$@" || { 336 args="$*" 337 die "$(eval_gettext "'\$args' is not a stash reference")" 338 } 339} 340 341apply_stash () { 342 343 assert_stash_like "$@" 344 345 git update-index -q --refresh || die "$(gettext "unable to refresh index")" 346 347 # current index state 348 c_tree=$(git write-tree)|| 349 die "$(gettext "Cannot apply a stash in the middle of a merge")" 350 351 unstashed_index_tree= 352 if test -n "$INDEX_OPTION" && test "$b_tree" != "$i_tree" && 353 test "$c_tree" != "$i_tree" 354 then 355 git diff-tree --binary$s^2^..$s^2 | git apply --cached 356 test $? -ne 0 && 357 die "$(gettext "Conflicts in index. Try without --index.")" 358 unstashed_index_tree=$(git write-tree)|| 359 die "$(gettext "Could not save index tree")" 360 git reset 361 fi 362 363 eval " 364 GITHEAD_$w_tree='Stashed changes'&& 365 GITHEAD_$c_tree='Updated upstream'&& 366 GITHEAD_$b_tree='Version stash was based on'&& 367export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree 368" 369 370 if test -n "$GIT_QUIET" 371 then 372 GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY 373 fi 374 if git merge-recursive$b_tree--$c_tree$w_tree 375 then 376 # No conflict 377 if test -n "$unstashed_index_tree" 378 then 379 git read-tree "$unstashed_index_tree" 380 else 381 a="$TMP-added" && 382 git diff-index --cached --name-only --diff-filter=A$c_tree>"$a" && 383 git read-tree --reset$c_tree&& 384 git update-index --add --stdin <"$a" || 385 die "$(gettext "Cannot unstage modified files")" 386 rm -f "$a" 387 fi 388 squelch= 389 if test -n "$GIT_QUIET" 390 then 391 squelch='>/dev/null 2>&1' 392 fi 393 (cd "$START_DIR" && eval "git status $squelch") || : 394 else 395 # Merge conflict; keep the exit status from merge-recursive 396 status=$? 397 if test -n "$INDEX_OPTION" 398 then 399 ( 400 gettext "Index was not unstashed." && 401 echo 402 ) >&2 403 fi 404 exit$status 405 fi 406} 407 408pop_stash() { 409 assert_stash_ref "$@" 410 411 apply_stash "$@" && 412 drop_stash "$@" 413} 414 415drop_stash () { 416 assert_stash_ref "$@" 417 418 git reflog delete --updateref --rewrite "${REV}" && 419 say "Dropped ${REV}($s)" || die "${REV}: Could not drop stash entry" 420 421 # clear_stash if we just dropped the last stash entry 422 git rev-parse --verify "$ref_stash@{0}" > /dev/null 2>&1 || clear_stash 423} 424 425apply_to_branch () { 426 test -n "$1" || die "$(gettext "No branch name specified")" 427 branch=$1 428 shift 1 429 430 set -- --index "$@" 431 assert_stash_like "$@" 432 433 git checkout -b$branch$REV^ && 434 apply_stash "$@" && { 435 test -z "$IS_STASH_REF" || drop_stash "$@" 436 } 437} 438 439PARSE_CACHE='--not-parsed' 440# The default command is "save" if nothing but options are given 441seen_non_option= 442for opt 443do 444 case "$opt" in 445 -*) ;; 446 *) seen_non_option=t; break ;; 447 esac 448done 449 450test -n "$seen_non_option" || set "save" "$@" 451 452# Main command set 453case "$1" in 454list) 455 shift 456 list_stash "$@" 457 ;; 458show) 459 shift 460 show_stash "$@" 461 ;; 462save) 463 shift 464 save_stash "$@" 465 ;; 466apply) 467 shift 468 apply_stash "$@" 469 ;; 470clear) 471 shift 472 clear_stash "$@" 473 ;; 474create) 475 if test$#-gt 0 && test "$1" = create 476 then 477 shift 478 fi 479 create_stash "$*" && echo "$w_commit" 480 ;; 481drop) 482 shift 483 drop_stash "$@" 484 ;; 485pop) 486 shift 487 pop_stash "$@" 488 ;; 489branch) 490 shift 491 apply_to_branch "$@" 492 ;; 493*) 494 case$#in 495 0) 496 save_stash && 497 say "$(gettext "(To restore them type \"git stash apply\")")" 498;; 499*) 500 usage 501esac 502;; 503esac