]>
Commit | Line | Data |
---|---|---|
f2c66ed1 NS |
1 | #!/bin/sh |
2 | # Copyright (c) 2007, Nanako Shiraishi | |
3 | ||
4 | USAGE='[ | list | show | apply | clear]' | |
5 | ||
6 | . git-sh-setup | |
7 | require_work_tree | |
8 | ||
9 | TMP="$GIT_DIR/.git-stash.$$" | |
10 | trap 'rm -f "$TMP-*"' 0 | |
11 | ||
12 | ref_stash=refs/stash | |
13 | ||
14 | no_changes () { | |
15 | git-diff-index --quiet --cached HEAD && | |
16 | git-diff-files --quiet | |
17 | } | |
18 | ||
19 | clear_stash () { | |
20 | logfile="$GIT_DIR/logs/$ref_stash" && | |
21 | mkdir -p "$(dirname "$logfile")" && | |
22 | : >"$logfile" | |
23 | } | |
24 | ||
25 | save_stash () { | |
26 | if no_changes | |
27 | then | |
28 | echo >&2 'No local changes to save' | |
29 | exit 0 | |
30 | fi | |
31 | test -f "$GIT_DIR/logs/$ref_stash" || | |
32 | clear_stash || die "Cannot initialize stash" | |
33 | ||
34 | # state of the base commit | |
35 | if b_commit=$(git-rev-parse --verify HEAD) | |
36 | then | |
37 | head=$(git-log --abbrev-commit --pretty=oneline -n 1 HEAD) | |
38 | else | |
39 | die "You do not have the initial commit yet" | |
40 | fi | |
41 | ||
42 | if branch=$(git-symbolic-ref -q HEAD) | |
43 | then | |
44 | branch=${branch#refs/heads/} | |
45 | else | |
46 | branch='(no branch)' | |
47 | fi | |
48 | msg=$(printf '%s: %s' "$branch" "$head") | |
49 | ||
50 | # state of the index | |
51 | i_tree=$(git-write-tree) && | |
52 | i_commit=$(printf 'index on %s' "$msg" | | |
53 | git-commit-tree $i_tree -p $b_commit) || | |
54 | die "Cannot save the current index state" | |
55 | ||
56 | # state of the working tree | |
57 | w_tree=$( ( | |
58 | GIT_INDEX_FILE="$TMP-index" && | |
59 | export GIT_INDEX_FILE && | |
60 | ||
61 | rm -f "$TMP-index" && | |
62 | git-read-tree $i_tree && | |
63 | git-add -u && | |
64 | git-write-tree && | |
65 | rm -f "$TMP-index" | |
66 | ) ) || | |
67 | die "Cannot save the current worktree state" | |
68 | ||
69 | # create the stash | |
70 | w_commit=$(printf 'WIP on %s' "$msg" | | |
71 | git-commit-tree $w_tree -p $b_commit -p $i_commit) || | |
72 | die "Cannot record working tree state" | |
73 | ||
74 | git-update-ref -m "$msg" $ref_stash $w_commit || | |
75 | die "Cannot save the current status" | |
76 | printf >&2 'Saved WIP on %s\n' "$msg" | |
77 | } | |
78 | ||
79 | list_stash () { | |
80 | git-log --pretty=oneline -g "$@" $ref_stash | | |
81 | sed -n -e 's/^[.0-9a-f]* refs\///p' | |
82 | } | |
83 | ||
84 | show_stash () { | |
85 | flags=$(git-rev-parse --no-revs --flags "$@") | |
86 | if test -z "$flags" | |
87 | then | |
88 | flags=--stat | |
89 | fi | |
90 | s=$(git-rev-parse --revs-only --no-flags --default $ref_stash "$@") | |
91 | ||
92 | w_commit=$(git-rev-parse --verify "$s") && | |
93 | b_commit=$(git-rev-parse --verify "$s^") && | |
94 | git-diff $flags $b_commit $w_commit | |
95 | } | |
96 | ||
97 | apply_stash () { | |
98 | git-diff-files --quiet || | |
99 | die 'Cannot restore on top of a dirty state' | |
100 | ||
101 | # current index state | |
102 | c_tree=$(git-write-tree) || | |
103 | die 'Cannot apply a stash in the middle of a merge' | |
104 | ||
105 | s=$(git-rev-parse --revs-only --no-flags --default $ref_stash "$@") && | |
106 | w_tree=$(git-rev-parse --verify "$s:") && | |
107 | b_tree=$(git-rev-parse --verify "$s^:") || | |
108 | die "$*: no valid stashed state found" | |
109 | ||
110 | eval " | |
111 | GITHEAD_$w_tree='Stashed changes' && | |
112 | GITHEAD_$c_tree='Updated upstream' && | |
113 | GITHEAD_$b_tree='Version stash was based on' && | |
114 | export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree | |
115 | " | |
116 | ||
117 | if git-merge-recursive $b_tree -- $c_tree $w_tree | |
118 | then | |
119 | # No conflict | |
120 | a="$TMP-added" && | |
121 | git-diff --cached --name-only --diff-filter=A $c_tree >"$a" && | |
122 | git-read-tree --reset $c_tree && | |
123 | git-update-index --add --stdin <"$a" || | |
124 | die "Cannot unstage modified files" | |
125 | git-status | |
126 | rm -f "$a" | |
127 | else | |
128 | # Merge conflict; keep the exit status from merge-recursive | |
129 | exit | |
130 | fi | |
131 | } | |
132 | ||
133 | # Main command set | |
134 | case "$1" in | |
9488e875 | 135 | list | '') |
006a8664 | 136 | test $# -gt 0 && shift |
f2c66ed1 NS |
137 | if test $# = 0 |
138 | then | |
139 | set x -n 10 | |
140 | shift | |
141 | fi | |
142 | list_stash "$@" | |
143 | ;; | |
144 | show) | |
145 | shift | |
146 | show_stash "$@" | |
147 | ;; | |
148 | apply) | |
149 | shift | |
150 | apply_stash "$@" | |
151 | ;; | |
152 | clear) | |
153 | clear_stash | |
154 | ;; | |
9488e875 | 155 | save) |
f2c66ed1 NS |
156 | save_stash && git-reset --hard |
157 | ;; | |
158 | *) | |
159 | usage | |
160 | esac |