stash: convert save to builtin

Add stash save to the helper and delete functions which are no longer needed (`show_help()`, `save_stash()`, `push_stash()`, `create_stash()`, `clear_stash()`, `untracked_files()` and `no_changes()`). Signed-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Paul-Sebastian Ungureanu committed Feb 25, 2019 at 23:16 UTC 64fe9c26a479082eb80a9d68e8b3b7686e8c2b26
2 files changed +52 -326
builtin/stash--helper.c
+50
@@ -26,6 +26,8 @@ static const char * const git_stash_helper_usage[] = {
26 N_("git stash--helper [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
27 " [-u|--include-untracked] [-a|--all] [-m|--message <message>]\n"
28 " [--] [<pathspec>...]]"),
29 + N_("git stash--helper save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
30 + " [-u|--include-untracked] [-a|--all] [<message>]"),
31 NULL
32 };
33
@@ -81,6 +83,12 @@ static const char * const git_stash_helper_push_usage[] = {
83 NULL
84 };
85
86 +static const char * const git_stash_helper_save_usage[] = {
87 + N_("git stash--helper save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]\n"
88 + " [-u|--include-untracked] [-a|--all] [<message>]"),
89 + NULL
90 +};
91 +
92 static const char *ref_stash = "refs/stash";
93 static struct strbuf stash_index_path = STRBUF_INIT;
94
@@ -1486,6 +1494,46 @@ static int push_stash(int argc, const char **argv, const char *prefix)
1494 include_untracked);
1495 }
1496
1497 +static int save_stash(int argc, const char **argv, const char *prefix)
1498 +{
1499 + int keep_index = -1;
1500 + int patch_mode = 0;
1501 + int include_untracked = 0;
1502 + int quiet = 0;
1503 + int ret = 0;
1504 + const char *stash_msg = NULL;
1505 + struct pathspec ps;
1506 + struct strbuf stash_msg_buf = STRBUF_INIT;
1507 + struct option options[] = {
1508 + OPT_BOOL('k', "keep-index", &keep_index,
1509 + N_("keep index")),
1510 + OPT_BOOL('p', "patch", &patch_mode,
1511 + N_("stash in patch mode")),
1512 + OPT__QUIET(&quiet, N_("quiet mode")),
1513 + OPT_BOOL('u', "include-untracked", &include_untracked,
1514 + N_("include untracked files in stash")),
1515 + OPT_SET_INT('a', "all", &include_untracked,
1516 + N_("include ignore files"), 2),
1517 + OPT_STRING('m', "message", &stash_msg, "message",
1518 + N_("stash message")),
1519 + OPT_END()
1520 + };
1521 +
1522 + argc = parse_options(argc, argv, prefix, options,
1523 + git_stash_helper_save_usage,
1524 + PARSE_OPT_KEEP_DASHDASH);
1525 +
1526 + if (argc)
1527 + stash_msg = strbuf_join_argv(&stash_msg_buf, argc, argv, ' ');
1528 +
1529 + memset(&ps, 0, sizeof(ps));
1530 + ret = do_push_stash(ps, stash_msg, quiet, keep_index,
1531 + patch_mode, include_untracked);
1532 +
1533 + strbuf_release(&stash_msg_buf);
1534 + return ret;
1535 +}
1536 +
1537 int cmd_stash__helper(int argc, const char **argv, const char *prefix)
1538 {
1539 pid_t pid = getpid();
@@ -1526,6 +1574,8 @@ int cmd_stash__helper(int argc, const char **argv, const char *prefix)
1574 return !!create_stash(argc, argv, prefix);
1575 else if (!strcmp(argv[0], "push"))
1576 return !!push_stash(argc, argv, prefix);
1577 + else if (!strcmp(argv[0], "save"))
1578 + return !!save_stash(argc, argv, prefix);
1579
1580 usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
1581 git_stash_helper_usage, options);
git-stash.sh
+2 -326
@@ -36,331 +36,6 @@ else
36 reset_color=
37 fi
38
39 -no_changes () {
40 - git diff-index --quiet --cached HEAD --ignore-submodules -- "$@" &&
41 - git diff-files --quiet --ignore-submodules -- "$@" &&
42 - (test -z "$untracked" || test -z "$(untracked_files "$@")")
43 -}
44 -
45 -untracked_files () {
46 - if test "$1" = "-z"
47 - then
48 - shift
49 - z=-z
50 - else
51 - z=
52 - fi
53 - excl_opt=--exclude-standard
54 - test "$untracked" = "all" && excl_opt=
55 - git ls-files -o $z $excl_opt -- "$@"
56 -}
57 -
58 -prepare_fallback_ident () {
59 - if ! git -c user.useconfigonly=yes var GIT_COMMITTER_IDENT >/dev/null 2>&1
60 - then
61 - GIT_AUTHOR_NAME="git stash"
62 - GIT_AUTHOR_EMAIL=git@stash
63 - GIT_COMMITTER_NAME="git stash"
64 - GIT_COMMITTER_EMAIL=git@stash
65 - export GIT_AUTHOR_NAME
66 - export GIT_AUTHOR_EMAIL
67 - export GIT_COMMITTER_NAME
68 - export GIT_COMMITTER_EMAIL
69 - fi
70 -}
71 -
72 -clear_stash () {
73 - if test $# != 0
74 - then
75 - die "$(gettext "git stash clear with parameters is unimplemented")"
76 - fi
77 - if current=$(git rev-parse --verify --quiet $ref_stash)
78 - then
79 - git update-ref -d $ref_stash $current
80 - fi
81 -}
82 -
83 -create_stash () {
84 -
85 - prepare_fallback_ident
86 -
87 - stash_msg=
88 - untracked=
89 - while test $# != 0
90 - do
91 - case "$1" in
92 - -m|--message)
93 - shift
94 - stash_msg=${1?"BUG: create_stash () -m requires an argument"}
95 - ;;
96 - -m*)
97 - stash_msg=${1#-m}
98 - ;;
99 - --message=*)
100 - stash_msg=${1#--message=}
101 - ;;
102 - -u|--include-untracked)
103 - shift
104 - untracked=${1?"BUG: create_stash () -u requires an argument"}
105 - ;;
106 - --)
107 - shift
108 - break
109 - ;;
110 - esac
111 - shift
112 - done
113 -
114 - git update-index -q --refresh
115 - if no_changes "$@"
116 - then
117 - exit 0
118 - fi
119 -
120 - # state of the base commit
121 - if b_commit=$(git rev-parse --verify HEAD)
122 - then
123 - head=$(git rev-list --oneline -n 1 HEAD --)
124 - else
125 - die "$(gettext "You do not have the initial commit yet")"
126 - fi
127 -
128 - if branch=$(git symbolic-ref -q HEAD)
129 - then
130 - branch=${branch#refs/heads/}
131 - else
132 - branch='(no branch)'
133 - fi
134 - msg=$(printf '%s: %s' "$branch" "$head")
135 -
136 - # state of the index
137 - i_tree=$(git write-tree) &&
138 - i_commit=$(printf 'index on %s\n' "$msg" |
139 - git commit-tree $i_tree -p $b_commit) ||
140 - die "$(gettext "Cannot save the current index state")"
141 -
142 - if test -n "$untracked"
143 - then
144 - # Untracked files are stored by themselves in a parentless commit, for
145 - # ease of unpacking later.
146 - u_commit=$(
147 - untracked_files -z "$@" | (
148 - GIT_INDEX_FILE="$TMPindex" &&
149 - export GIT_INDEX_FILE &&
150 - rm -f "$TMPindex" &&
151 - git update-index -z --add --remove --stdin &&
152 - u_tree=$(git write-tree) &&
153 - printf 'untracked files on %s\n' "$msg" | git commit-tree $u_tree &&
154 - rm -f "$TMPindex"
155 - ) ) || die "$(gettext "Cannot save the untracked files")"
156 -
157 - untracked_commit_option="-p $u_commit";
158 - else
159 - untracked_commit_option=
160 - fi
161 -
162 - if test -z "$patch_mode"
163 - then
164 -
165 - # state of the working tree
166 - w_tree=$( (
167 - git read-tree --index-output="$TMPindex" -m $i_tree &&
168 - GIT_INDEX_FILE="$TMPindex" &&
169 - export GIT_INDEX_FILE &&
170 - git diff-index --name-only -z HEAD -- "$@" >"$TMP-stagenames" &&
171 - git update-index -z --add --remove --stdin <"$TMP-stagenames" &&
172 - git write-tree &&
173 - rm -f "$TMPindex"
174 - ) ) ||
175 - die "$(gettext "Cannot save the current worktree state")"
176 -
177 - else
178 -
179 - rm -f "$TMP-index" &&
180 - GIT_INDEX_FILE="$TMP-index" git read-tree HEAD &&
181 -
182 - # find out what the user wants
183 - GIT_INDEX_FILE="$TMP-index" \
184 - git add--interactive --patch=stash -- "$@" &&
185 -
186 - # state of the working tree
187 - w_tree=$(GIT_INDEX_FILE="$TMP-index" git write-tree) ||
188 - die "$(gettext "Cannot save the current worktree state")"
189 -
190 - git diff-tree -p HEAD $w_tree -- >"$TMP-patch" &&
191 - test -s "$TMP-patch" ||
192 - die "$(gettext "No changes selected")"
193 -
194 - rm -f "$TMP-index" ||
195 - die "$(gettext "Cannot remove temporary index (can't happen)")"
196 -
197 - fi
198 -
199 - # create the stash
200 - if test -z "$stash_msg"
201 - then
202 - stash_msg=$(printf 'WIP on %s' "$msg")
203 - else
204 - stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg")
205 - fi
206 - w_commit=$(printf '%s\n' "$stash_msg" |
207 - git commit-tree $w_tree -p $b_commit -p $i_commit $untracked_commit_option) ||
208 - die "$(gettext "Cannot record working tree state")"
209 -}
210 -
211 -push_stash () {
212 - keep_index=
213 - patch_mode=
214 - untracked=
215 - stash_msg=
216 - while test $# != 0
217 - do
218 - case "$1" in
219 - -k|--keep-index)
220 - keep_index=t
221 - ;;
222 - --no-keep-index)
223 - keep_index=n
224 - ;;
225 - -p|--patch)
226 - patch_mode=t
227 - # only default to keep if we don't already have an override
228 - test -z "$keep_index" && keep_index=t
229 - ;;
230 - -q|--quiet)
231 - GIT_QUIET=t
232 - ;;
233 - -u|--include-untracked)
234 - untracked=untracked
235 - ;;
236 - -a|--all)
237 - untracked=all
238 - ;;
239 - -m|--message)
240 - shift
241 - test -z ${1+x} && usage
242 - stash_msg=$1
243 - ;;
244 - -m*)
245 - stash_msg=${1#-m}
246 - ;;
247 - --message=*)
248 - stash_msg=${1#--message=}
249 - ;;
250 - --help)
251 - show_help
252 - ;;
253 - --)
254 - shift
255 - break
256 - ;;
257 - -*)
258 - option="$1"
259 - eval_gettextln "error: unknown option for 'stash push': \$option"
260 - usage
261 - ;;
262 - *)
263 - break
264 - ;;
265 - esac
266 - shift
267 - done
268 -
269 - eval "set $(git rev-parse --sq --prefix "$prefix" -- "$@")"
270 -
271 - if test -n "$patch_mode" && test -n "$untracked"
272 - then
273 - die "$(gettext "Can't use --patch and --include-untracked or --all at the same time")"
274 - fi
275 -
276 - test -n "$untracked" || git ls-files --error-unmatch -- "$@" >/dev/null || exit 1
277 -
278 - git update-index -q --refresh
279 - if no_changes "$@"
280 - then
281 - say "$(gettext "No local changes to save")"
282 - exit 0
283 - fi
284 -
285 - git reflog exists $ref_stash ||
286 - clear_stash || die "$(gettext "Cannot initialize stash")"
287 -
288 - create_stash -m "$stash_msg" -u "$untracked" -- "$@"
289 - git stash--helper store -m "$stash_msg" -q $w_commit ||
290 - die "$(gettext "Cannot save the current status")"
291 - say "$(eval_gettext "Saved working directory and index state \$stash_msg")"
292 -
293 - if test -z "$patch_mode"
294 - then
295 - test "$untracked" = "all" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=
296 - if test -n "$untracked" && test $# = 0
297 - then
298 - git clean --force --quiet -d $CLEAN_X_OPTION
299 - fi
300 -
301 - if test $# != 0
302 - then
303 - test -z "$untracked" && UPDATE_OPTION="-u" || UPDATE_OPTION=
304 - test "$untracked" = "all" && FORCE_OPTION="--force" || FORCE_OPTION=
305 - git add $UPDATE_OPTION $FORCE_OPTION -- "$@"
306 - git diff-index -p --cached --binary HEAD -- "$@" |
307 - git apply --index -R
308 - else
309 - git reset --hard -q
310 - fi
311 -
312 - if test "$keep_index" = "t" && test -n "$i_tree"
313 - then
314 - git read-tree --reset $i_tree
315 - git ls-files -z --modified -- "$@" |
316 - git checkout-index -z --force --stdin
317 - fi
318 - else
319 - git apply -R < "$TMP-patch" ||
320 - die "$(gettext "Cannot remove worktree changes")"
321 -
322 - if test "$keep_index" != "t"
323 - then
324 - git reset -q -- "$@"
325 - fi
326 - fi
327 -}
328 -
329 -save_stash () {
330 - push_options=
331 - while test $# != 0
332 - do
333 - case "$1" in
334 - --)
335 - shift
336 - break
337 - ;;
338 - -*)
339 - # pass all options through to push_stash
340 - push_options="$push_options $1"
341 - ;;
342 - *)
343 - break
344 - ;;
345 - esac
346 - shift
347 - done
348 -
349 - stash_msg="$*"
350 -
351 - if test -z "$stash_msg"
352 - then
353 - push_stash $push_options
354 - else
355 - push_stash $push_options -m "$stash_msg"
356 - fi
357 -}
358 -
359 -show_help () {
360 - exec git help stash
361 - exit 1
362 -}
363 -
39 #
40 # Parses the remaining options looking for flags and
41 # at most one revision defaulting to ${ref_stash}@{0}
@@ -425,7 +100,8 @@ show)
100 ;;
101 save)
102 shift
428 - save_stash "$@"
103 + cd "$START_DIR"
104 + git stash--helper save "$@"
105 ;;
106 push)
107 shift