{"thread":{"id":"45357","subject":"[PATCH] [RFC] Converting git stash to a builtin","startedAt":"2017-03-11T21:28:01Z","lastAt":"2017-03-11T21:28:01Z","messageCount":1,"participants":["Joel Teichroeb"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"313837","messageId":"20170311212735.28186-1-joel@teichroeb.net","threadId":"45357","inReplyTo":null,"subject":"[PATCH] [RFC] Converting git stash to a builtin","fromName":"Joel Teichroeb","fromEmail":"joel@teichroeb.net","sentAt":"2017-03-11T21:27:35Z","receivedAt":"2017-03-11T21:28:01Z","isPatch":true,"sender":{"key":"joel@teichroeb.net","avatar":"https://avatars.githubusercontent.com/u/240865?v=4"},"body":"I've been working on rewriting git stash as a c builtin and I have all\nbut three tests passing. I'm having a bit of trouble fixing them, as\nwell as a few other issues, so I'd really appreciate some help. Don't\nbother commenting on the small details yet as I still need to go\nthough the code to make sure it matches the code style guidelines.\n\nTest Summary Report\n-------------------\nt7601-merge-pull-config.sh                       (Wstat: 256 Tests: 14\nFailed: 2)\n  Failed tests:  11-12\n  Non-zero exit status: 1\nt3903-stash.sh                                   (Wstat: 256 Tests: 74\nFailed: 1)\n  Failed test:  69\n  Non-zero exit status: 1\n\nIt looks to be the same issue for both of these cases where\nmerge-recursive reports:\nerror: Your local changes to the following files would be overwritten by merge:\n        file\n        other-file\n\nwhich doesn't make sense as those files didn't exist before the merge.\nFurthermore if I take the existing git stash implementation and have\nit stop before running the merge-recursive command and then run it on\nthe commandline manually, I get the same issue. I've tried setting all\nthe same environment variables that the existing git stash\nimplementation does, but it doesn't help. It seems like there could be\na bug in merge-recursive, but I'm not sure how to track it down.\n\ngit stash uses the GIT_INDEX_FILE environment variable in order to not\ntrash the main index. I ended up doing things like this:\n\n    discard_cache();\n    ret = read_cache_from(index_path);\n    write_index_as_tree(orig_tree.hash, &the_index, index_path, 0, NULL);\n    discard_cache();\n    ret = read_cache_from(index_path);\n\nin order to have an empty cache. Could someone take a look at my uses\nof the index and point out better ways to do it?\n\nMy main goal right now is to cleanup the code and replace more of the\ncommands with native code.\n---\n Makefile          |    2 +-\n builtin.h         |    1 +\n builtin/stash.c   | 1286 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n git-stash.sh      |  731 ------------------------------\n git.c             |    1 +\n merge-recursive.c |    5 +-\n 6 files changed, 1291 insertions(+), 735 deletions(-)\n create mode 100644 builtin/stash.c\n delete mode 100755 git-stash.sh\n\ndiff --git a/Makefile b/Makefile\nindex ed68700ac..3c673cc7e 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -516,7 +516,6 @@ SCRIPT_SH += git-quiltimport.sh\n SCRIPT_SH += git-rebase.sh\n SCRIPT_SH += git-remote-testgit.sh\n SCRIPT_SH += git-request-pull.sh\n-SCRIPT_SH += git-stash.sh\n SCRIPT_SH += git-submodule.sh\n SCRIPT_SH += git-web--browse.sh\n \n@@ -949,6 +948,7 @@ BUILTIN_OBJS += builtin/send-pack.o\n BUILTIN_OBJS += builtin/shortlog.o\n BUILTIN_OBJS += builtin/show-branch.o\n BUILTIN_OBJS += builtin/show-ref.o\n+BUILTIN_OBJS += builtin/stash.o\n BUILTIN_OBJS += builtin/stripspace.o\n BUILTIN_OBJS += builtin/submodule--helper.o\n BUILTIN_OBJS += builtin/symbolic-ref.o\ndiff --git a/builtin.h b/builtin.h\nindex 9e4a89816..16e8a437d 100644\n--- a/builtin.h\n+++ b/builtin.h\n@@ -121,6 +121,7 @@ extern int cmd_shortlog(int argc, const char **argv, const char *prefix);\n extern int cmd_show(int argc, const char **argv, const char *prefix);\n extern int cmd_show_branch(int argc, const char **argv, const char *prefix);\n extern int cmd_status(int argc, const char **argv, const char *prefix);\n+extern int cmd_stash(int argc, const char **argv, const char *prefix);\n extern int cmd_stripspace(int argc, const char **argv, const char *prefix);\n extern int cmd_submodule__helper(int argc, const char **argv, const char *prefix);\n extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);\ndiff --git a/builtin/stash.c b/builtin/stash.c\nnew file mode 100644\nindex 000000000..c04d424f1\n--- /dev/null\n+++ b/builtin/stash.c\n@@ -0,0 +1,1286 @@\n+#include \"builtin.h\"\n+#include \"cache.h\"\n+#include \"parse-options.h\"\n+#include \"refs.h\"\n+#include \"tree.h\"\n+#include \"lockfile.h\"\n+#include \"object.h\"\n+#include \"tree-walk.h\"\n+#include \"cache-tree.h\"\n+#include \"unpack-trees.h\"\n+#include \"diff.h\"\n+#include \"revision.h\"\n+#include \"commit.h\"\n+#include \"diffcore.h\"\n+#include \"merge-recursive.h\"\n+#include \"argv-array.h\"\n+#include \"run-command.h\"\n+\n+static const char * const git_stash_usage[] = {\n+\tN_(\"git stash list [<options>]\"),\n+\tN_(\"git stash show [<stash>]\"),\n+\tN_(\"git stash drop [-q|--quiet] [<stash>]\"),\n+\tN_(\"git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]\"),\n+\tN_(\"git stash branch <branchname> [<stash>]\"),\n+\tN_(\"git stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\"),\n+\tN_(\"                [-u|--include-untracked] [-a|--all] [<message>]]\"),\n+\tN_(\"git stash clear\"),\n+\tN_(\"git stash create [<message>]\"),\n+\tN_(\"git stash store [-m|--message <message>] [-q|--quiet] <commit>\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_list_usage[] = {\n+\tN_(\"git stash list [<options>]\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_show_usage[] = {\n+\tN_(\"git stash show [<stash>]\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_drop_usage[] = {\n+\tN_(\"git stash drop [-q|--quiet] [<stash>]\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_pop_usage[] = {\n+\tN_(\"git stash pop [--index] [-q|--quiet] [<stash>]\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_apply_usage[] = {\n+\tN_(\"git stash apply [--index] [-q|--quiet] [<stash>]\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_branch_usage[] = {\n+\tN_(\"git stash branch <branchname> [<stash>]\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_save_usage[] = {\n+\tN_(\"git stash [save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\"),\n+\tN_(\"                [-u|--include-untracked] [-a|--all] [<message>]]\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_clear_usage[] = {\n+\tN_(\"git stash clear\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_create_usage[] = {\n+\tN_(\"git stash create [<message>]\"),\n+\tNULL\n+};\n+\n+static const char * const git_stash_store_usage[] = {\n+\tN_(\"git stash store [-m|--message <message>] [-q|--quiet] <commit>\"),\n+\tNULL\n+};\n+\n+static const char *ref_stash = \"refs/stash\";\n+static int quiet = 0;\n+static struct lock_file lock_file;\n+\n+struct stash_info {\n+\tunsigned char w_commit[20];\n+\tunsigned char b_commit[20];\n+\tunsigned char i_commit[20];\n+\tunsigned char u_commit[20];\n+\tunsigned char w_tree[20];\n+\tunsigned char b_tree[20];\n+\tunsigned char i_tree[20];\n+\tunsigned char u_tree[20];\n+\tconst char *message;\n+\tconst char *REV;\n+\tint is_stash_ref;\n+\tint has_u;\n+\tconst char *patch;\n+};\n+\n+int untracked_files(struct strbuf *out, int include_untracked, const char **argv)\n+{\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\tcp.git_cmd = 1;\n+\targv_array_push(&cp.args, \"ls-files\");\n+\targv_array_push(&cp.args, \"-o\");\n+\targv_array_push(&cp.args, \"-z\");\n+\tif (include_untracked != 2) {\n+\t\targv_array_push(&cp.args, \"--exclude-standard\");\n+\t}\n+\tif (argv) {\n+\t\targv_array_push(&cp.args, \"--\");\n+\t\targv_array_pushv(&cp.args, argv);\n+\t}\n+\treturn pipe_command(&cp, NULL, 0, out, 0, NULL, 0);\n+}\n+\n+static int check_no_changes(const char *prefix, int include_untracked, const char **argv)\n+{\n+\tstruct argv_array args1;\n+\tstruct argv_array args2;\n+\tstruct strbuf out = STRBUF_INIT;\n+\targv_array_init(&args1);\n+\targv_array_push(&args1, \"diff-index\");\n+\targv_array_push(&args1, \"--quiet\");\n+\targv_array_push(&args1, \"--cached\");\n+\targv_array_push(&args1, \"HEAD\");\n+\targv_array_push(&args1, \"--ignore-submodules\");\n+\targv_array_push(&args1, \"--\");\n+\tif (argv) {\n+\t\targv_array_pushv(&args1, argv);\n+\t}\n+\targv_array_init(&args2);\n+\targv_array_push(&args2, \"diff-files\");\n+\targv_array_push(&args2, \"--quiet\");\n+\targv_array_push(&args2, \"--ignore-submodules\");\n+\tif (argv) {\n+\t\targv_array_push(&args2, \"--\");\n+\t\targv_array_pushv(&args2, argv);\n+\t}\n+\tif (include_untracked) {\n+\t\tuntracked_files(&out, include_untracked, argv);\n+\t}\n+\treturn cmd_diff_index(args1.argc, args1.argv, prefix) == 0 &&\n+\t\t\tcmd_diff_files(args2.argc, args2.argv, prefix) == 0 &&\n+\t\t\t(!include_untracked || out.len == 0);\n+}\n+\n+static int get_stash_info(struct stash_info *info, const char *commit)\n+{\n+\tstruct strbuf w_commit_rev = STRBUF_INIT;\n+\tstruct strbuf b_commit_rev = STRBUF_INIT;\n+\tstruct strbuf i_commit_rev = STRBUF_INIT;\n+\tstruct strbuf u_commit_rev = STRBUF_INIT;\n+\tstruct strbuf w_tree_rev = STRBUF_INIT;\n+\tstruct strbuf b_tree_rev = STRBUF_INIT;\n+\tstruct strbuf i_tree_rev = STRBUF_INIT;\n+\tstruct strbuf u_tree_rev = STRBUF_INIT;\n+\tstruct object_context unused;\n+\tstruct strbuf commit_buf = STRBUF_INIT;\n+\tint ret;\n+\tconst char *REV = commit;\n+\tinfo->is_stash_ref = 0;\n+\n+\n+\tif (commit == NULL) {\n+\t\tREV = \"refs/stash@{0}\";\n+\t} else if (strlen(commit) < 3) {\n+\t\tstrbuf_addf(&commit_buf, \"refs/stash@{%s}\", commit);\n+\t\tREV = commit_buf.buf;\n+\t}\n+\tinfo->REV = REV;\n+\n+\tstrbuf_addf(&w_commit_rev, \"%s\", REV);\n+\tstrbuf_addf(&b_commit_rev, \"%s^1\", REV);\n+\tstrbuf_addf(&i_commit_rev, \"%s^2\", REV);\n+\tstrbuf_addf(&u_commit_rev, \"%s^3\", REV);\n+\tstrbuf_addf(&w_tree_rev, \"%s:\", REV);\n+\tstrbuf_addf(&b_tree_rev, \"%s^1:\", REV);\n+\tstrbuf_addf(&i_tree_rev, \"%s^2:\", REV);\n+\tstrbuf_addf(&u_tree_rev, \"%s^3:\", REV);\n+\n+\n+\tret = (\n+\t\tget_sha1_with_context(w_commit_rev.buf, 0, info->w_commit, &unused) == 0 &&\n+\t\tget_sha1_with_context(b_commit_rev.buf, 0, info->b_commit, &unused) == 0 &&\n+\t\tget_sha1_with_context(i_commit_rev.buf, 0, info->i_commit, &unused) == 0 &&\n+\t\tget_sha1_with_context(w_tree_rev.buf, 0, info->w_tree, &unused) == 0 &&\n+\t\tget_sha1_with_context(b_tree_rev.buf, 0, info->b_tree, &unused) == 0 &&\n+\t\tget_sha1_with_context(i_tree_rev.buf, 0, info->i_tree, &unused) == 0);\n+\n+\tinfo->has_u = get_sha1_with_context(u_commit_rev.buf, 0, info->u_commit, &unused) == 0 &&\n+\tget_sha1_with_context(u_tree_rev.buf, 0, info->u_tree, &unused) == 0;\n+\n+\t// TODO: Properly check for stash refs\n+\tinfo->is_stash_ref = REV[4] == '/';\n+\n+\treturn ret;\n+}\n+\n+struct stash_create_callback_data {\n+\tconst char **argv;\n+};\n+\n+static void stash_create_callback(struct diff_queue_struct *q,\n+\t\t\t\tstruct diff_options *opt, void *cbdata)\n+{\n+\tint i;\n+\tstruct stat st;\n+\tstruct stash_create_callback_data *data = cbdata;\n+\n+\tfor (i = 0; i < q->nr; i++) {\n+\t\tstruct diff_filepair *p = q->queue[i];\n+\t\tconst char *path = p->one->path;\n+\t\tif (data->argv) {\n+\t\t\tint found = 0;\n+\t\t\tint i = 0;\n+\t\t\tconst char *arg = data->argv[i++];\n+\t\t\twhile (arg != NULL) {\n+\t\t\t\tif (strcmp(arg, path) == 0) {\n+\t\t\t\t\tfound = 1;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\targ = data->argv[i++];\n+\t\t\t}\n+\t\t\tif (found == 0) {\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n+\t\tremove_file_from_index(&the_index, path);\n+\t\tif (!lstat(path, &st))\n+\t\t\tadd_to_index(&the_index, path, &st, 0);\n+\n+\t}\n+}\n+\n+static int do_create_stash(struct stash_info *stash_info, const char *prefix,\n+\tconst char *message, int include_untracked, int patch, const char **argv)\n+{\n+\tstruct object_id curr_head;\n+\tchar *branch_path = NULL;\n+\tconst char *branch_name = NULL;\n+\tunsigned char i_tree[20];\n+\tunsigned char w_tree[20];\n+\tunsigned char u_tree[20];\n+\tunsigned char w_commit[20];\n+\tunsigned char i_commit[20];\n+\tunsigned char b_commit[20];\n+\tunsigned char u_commit[20];\n+\tstruct commit_list *parents = NULL;\n+\tint ret;\n+\tstruct strbuf out = STRBUF_INIT;\n+\tstruct pretty_print_context ctx = {0};\n+\n+\tstruct commit *c = NULL;\n+\tconst char *hash;\n+\tstruct unpack_trees_options opts;\n+\tint nr_trees = 1;\n+\tstruct tree_desc t[MAX_UNPACK_TREES];\n+\tstruct tree *tree;\n+\tstruct rev_info rev;\n+\tint cached = 0;\n+\tstruct stash_create_callback_data data;\n+\tstruct object *obj;\n+\tstruct strbuf out2 = STRBUF_INIT;\n+\tstruct strbuf out3 = STRBUF_INIT;\n+\n+\trefresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);\n+\tif (check_no_changes(prefix, include_untracked, argv))\n+\t\treturn 0;\n+\n+\tif (get_sha1_tree(\"HEAD\", b_commit)) {\n+\t\tprintf(\"You do not have the initial commit yet\");\n+\t\treturn 1;\n+\t}\n+\n+\tbranch_path = resolve_refdup(\"HEAD\", 0, curr_head.hash, NULL);\n+\n+\tif (branch_path == NULL) {\n+\t\tbranch_name = \"(no_branch)\";\n+\t} else {\n+\t\tskip_prefix(branch_path, \"refs/heads/\", &branch_name);\n+\t}\n+\n+\tc = lookup_commit(b_commit);\n+\n+\tctx.output_encoding = get_log_output_encoding();\n+\tctx.abbrev = 1;\n+\tctx.fmt = CMIT_FMT_ONELINE;\n+\thash = find_unique_abbrev(c->object.oid.hash, DEFAULT_ABBREV);\n+\tret = write_cache_as_tree(i_tree, 0, NULL);\n+\n+\tstrbuf_addf(&out, \"%s: %s \", branch_name, hash);\n+\n+\tpretty_print_commit(&ctx, c, &out);\n+\n+\n+\tcommit_list_insert(lookup_commit(b_commit), &parents);\n+\n+\tret = commit_tree(out.buf, out.len, i_tree, parents, i_commit, NULL, NULL);\n+\n+\n+\n+\tif (include_untracked) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct child_process cp2 = CHILD_PROCESS_INIT;\n+\t\tstruct child_process cp3 = CHILD_PROCESS_INIT;\n+\t\tstruct strbuf out4 = STRBUF_INIT;\n+\t\tstruct object_id orig_tree;\n+\t\tconst char *index_path = \".git/foocache1\";\n+\t\tset_alternate_index_output(index_path);\n+\t\tcp.git_cmd = 1;\n+\t\targv_array_push(&cp.args, \"ls-files\");\n+\t\targv_array_push(&cp.args, \"-o\");\n+\t\targv_array_push(&cp.args, \"-z\");\n+\t\tif (include_untracked != 2) {\n+\t\t\targv_array_push(&cp.args, \"--exclude-standard\");\n+\t\t}\n+\t\tif (argv) {\n+\t\t\targv_array_push(&cp.args, \"--\");\n+\t\t\targv_array_pushv(&cp.args, argv);\n+\t\t}\n+\t\tpipe_command(&cp, NULL, 0, &out4, 0, NULL, 0);\n+\n+\t\tcp2.git_cmd = 1;\n+\t\targv_array_push(&cp2.args, \"update-index\");\n+\t\targv_array_push(&cp2.args, \"-z\");\n+\t\targv_array_push(&cp2.args, \"--add\");\n+\t\targv_array_push(&cp2.args, \"--remove\");\n+\t\targv_array_push(&cp2.args, \"--stdin\");\n+\t\targv_array_pushf(&cp2.env_array, \"GIT_INDEX_FILE=%s\", index_path);\n+\n+\t\tpipe_command(&cp2, out4.buf, out4.len, NULL, 0, NULL, 0);\n+\n+\t\tdiscard_cache();\n+\t\tret = read_cache_from(index_path);\n+\t\twrite_index_as_tree(orig_tree.hash, &the_index, index_path, 0, NULL);\n+\t\tdiscard_cache();\n+\t\tret = read_cache_from(index_path);\n+\n+\t\tret = write_cache_as_tree(u_tree, 0, NULL);\n+\t\tstrbuf_addf(&out3, \"untracked files on %s\", out.buf);\n+\n+\t\tret = commit_tree(out3.buf, out3.len, u_tree, NULL, u_commit, NULL, NULL);\n+\n+\t\tset_alternate_index_output(\".git/index\");\n+\t\tdiscard_cache();\n+\t\tread_cache();\n+\n+\t\targv_array_push(&cp3.args, \"rm\");\n+\t\targv_array_push(&cp3.args, \"-f\");\n+\t\targv_array_push(&cp3.args, index_path);\n+\t\tret = run_command(&cp3);\n+\n+\n+\t}\n+\n+\n+\tif (patch) {\n+\t\tconst char *index_path = \".git/foocache2\";\n+\t\tstruct argv_array args;\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct child_process cp2 = CHILD_PROCESS_INIT;\n+\t\tstruct strbuf out = STRBUF_INIT;\n+\n+\t\targv_array_init(&args);\n+\t\targv_array_push(&args, \"read-tree\");\n+\t\targv_array_push(&args, \"HEAD\");\n+\t\targv_array_pushf(&args, \"--index-output=%s\", index_path);\n+\t\tcmd_read_tree(args.argc, args.argv, prefix);\n+\n+\t\tcp2.git_cmd = 1;\n+\t\targv_array_push(&cp2.args, \"add--interactive\");\n+\t\targv_array_push(&cp2.args, \"--patch=stash\");\n+\t\targv_array_push(&cp2.args, \"--\");\n+\t\targv_array_pushf(&cp2.env_array, \"GIT_INDEX_FILE=%s\", index_path);\n+\t\tret = run_command(&cp2);\n+\n+\t\tdiscard_cache();\n+\t\tread_cache_from(index_path);\n+\n+\t\tret = write_cache_as_tree(w_tree, 0, NULL);\n+\n+\t\tcp.git_cmd = 1;\n+\t\targv_array_push(&cp.args, \"diff-tree\");\n+\t\targv_array_push(&cp.args, \"-p\");\n+\t\targv_array_push(&cp.args, \"HEAD\");\n+\t\targv_array_push(&cp.args, sha1_to_hex(w_tree));\n+\t\targv_array_push(&cp.args, \"--\");\n+\t\tpipe_command(&cp, NULL, 0, &out, 0, NULL, 0);\n+\t\tif (out.len == 0) {\n+\t\t\tdie(\"TODO error\");\n+\t\t}\n+\n+\t\tstash_info->patch = out.buf;\n+\n+\t\tset_alternate_index_output(\".git/index\");\n+\t\tdiscard_cache();\n+\t\tread_cache();\n+\n+\t} else {\n+\t\tconst char *index_path = \".git/foocache3\";\n+\t\tstruct object_id orig_tree;\n+\n+\t\tdiscard_cache();\n+\t\ttree = parse_tree_indirect(i_tree);\n+\t\tprime_cache_tree(&the_index, tree);\n+\t\twrite_index_as_tree(orig_tree.hash, &the_index, index_path, 0, NULL);\n+\t\tdiscard_cache();\n+\n+\t\tread_cache_from(index_path);\n+\n+\n+\t\tmemset(&opts, 0, sizeof(opts));\n+\n+\t\tparse_tree(tree);\n+\n+\t\topts.head_idx = 1;\n+\t\topts.src_index = &the_index;\n+\t\topts.dst_index = &the_index;\n+\t\topts.merge = 1;\n+\t\topts.fn = oneway_merge;\n+\n+\t\tinit_tree_desc(t, tree->buffer, tree->size);\n+\n+\t\tif (unpack_trees(nr_trees, t, &opts))\n+\t\t\treturn -1;\n+\n+\t\tinit_revisions(&rev, prefix);\n+\t\tsetup_revisions(0, NULL, &rev, NULL);\n+\t\trev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;\n+\t\tdata.argv = argv;\n+\t\trev.diffopt.format_callback_data = &data;\n+\t\trev.diffopt.format_callback = stash_create_callback;\n+\t\tdiff_setup_done(&rev.diffopt);\n+\t\tobj = parse_object(b_commit);\n+\t\tadd_pending_object(&rev, obj, \"\");\n+\t\tret = run_diff_index(&rev, cached);\n+\n+\t\tif (ret != 0) {\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\tret = write_cache_as_tree(w_tree, 0, NULL);\n+\t\tdiscard_cache();\n+\t\tread_cache();\n+\t}\n+\tparents = NULL;\n+\n+\tif (include_untracked) {\n+\t\tcommit_list_insert(lookup_commit(u_commit), &parents);\n+\t}\n+\n+\tcommit_list_insert(lookup_commit(i_commit), &parents);\n+\tcommit_list_insert(lookup_commit(b_commit), &parents);\n+\n+\n+\n+\tif (message != NULL && strlen(message) != 0) {\n+\t\tstrbuf_addf(&out2, \"On %s: %s\", branch_name, message);\n+\t} else {\n+\t\tstrbuf_addf(&out2, \"WIP on %s \", out.buf);\n+\t}\n+\n+\tret = commit_tree(out2.buf, out2.len, w_tree, parents, w_commit, NULL, NULL);\n+\n+\tif (stash_info) {\n+\t\tmemcpy(stash_info->w_commit, w_commit, 20);\n+\t\tmemcpy(stash_info->i_tree, i_tree, 20);\n+\t\tstash_info->message = out2.buf;\n+\t}\n+\n+\tfree(branch_path);\n+\n+\treturn 0;\n+}\n+\n+static int create_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tint include_untracked = 0;\n+\tconst char *message = NULL;\n+\tstruct stash_info info;\n+\tint result;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL('u', \"include-untracked\", &include_untracked,\n+\t\t\t N_(\"stash untracked filed\")),\n+\t\tOPT_STRING('m', \"message\", &message, N_(\"message\"),\n+\t\t\t N_(\"stash commit message\")),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_create_usage, 0);\n+\n+\tif (argc != 0) {\n+\t\tstruct strbuf out = STRBUF_INIT;\n+\t\tint i;\n+\t\tfor (i = 0; i < argc; ++i) {\n+\t\t\tif (i != 0) {\n+\t\t\t\tstrbuf_addf(&out, \" \");\n+\t\t\t}\n+\t\t\tstrbuf_addf(&out, \"%s\", argv[i]);\n+\t\t}\n+\t\tmessage = out.buf;\n+\t}\n+\n+\n+\tresult = do_create_stash(&info, prefix, message, include_untracked, 0, NULL);\n+\tprintf(\"%s\\n\", sha1_to_hex(info.w_commit));\n+\treturn result;\n+}\n+\n+static int do_store_stash(const char *prefix, const char *message, unsigned char w_commit[20])\n+{\n+\treturn update_ref(message, ref_stash, w_commit, NULL, REF_FORCE_CREATE_REFLOG, UPDATE_REFS_DIE_ON_ERR);\n+}\n+\n+static int store_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *message = NULL;\n+\tconst char *commit = NULL;\n+\tunsigned char sha1[20];\n+\tstruct option options[] = {\n+\t\tOPT_STRING('m', \"message\", &message, N_(\"message\"),\n+\t\t\t N_(\"stash commit message\")),\n+\t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_store_usage, 0);\n+\n+\tif (message == NULL) {\n+\t\tmessage = \"Create via \\\"git stash store\\\".\";\n+\t}\n+\n+\tif (argc == 0) {\n+\t\tdie(\"no commit?\");\n+\t}\n+\n+\tcommit = argv[0];\n+\n+\tif (get_sha1(commit, sha1)) {\n+\t\tdie(\"%s: not a valid SHA1\", commit);\n+\t}\n+\n+\treturn do_store_stash(prefix, message, sha1);\n+}\n+\n+static int do_clear_stash(void)\n+{\n+\tunsigned char w_commit[20];\n+\tstruct object_context unused;\n+\tint ret;\n+\tret = get_sha1_with_context(ref_stash, 0, w_commit, &unused);\n+\tif (ret != 0) {\n+\t\treturn 0;\n+\t}\n+\treturn delete_ref(\"\", ref_stash, w_commit, 0);\n+}\n+\n+static int clear_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_clear_usage, 0);\n+\n+\treturn do_clear_stash();\n+}\n+\n+static int reset_tree(unsigned char i_tree[20], int update, int reset)\n+{\n+\tstruct unpack_trees_options opts;\n+\tint nr_trees = 1;\n+\tstruct tree_desc t[MAX_UNPACK_TREES];\n+\tstruct tree *tree;\n+\tint ret;\n+\n+\tret = refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);\n+\tif (ret != 0) {\n+\t\tprintf(\"asdf1\\n\");\n+\t\treturn ret;\n+\t}\n+\thold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);\n+\n+\tmemset(&opts, 0, sizeof(opts));\n+\n+\ttree = parse_tree_indirect(i_tree);\n+\tret = parse_tree(tree);\n+\tif (ret != 0) {\n+\t\tprintf(\"asdf3\\n\");\n+\t\treturn ret;\n+\t}\n+\tinit_tree_desc(t, tree->buffer, tree->size);\n+\n+\topts.head_idx = 1;\n+\topts.src_index = &the_index;\n+\topts.dst_index = &the_index;\n+\topts.merge = 1;\n+\topts.reset = reset;\n+\topts.update = update;\n+\topts.fn = oneway_merge;\n+\n+\n+\tif (unpack_trees(nr_trees, t, &opts))\n+\t\treturn 1;\n+\n+\n+\tif (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) {\n+\t\terror(_(\"unable to write new index file\"));\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int do_push_stash(const char *prefix, const char *message,\n+\t\tint keep_index, int include_untracked, int patch, const char **argv)\n+{\n+\tint result;\n+\tstruct stash_info info;\n+\n+\tif (patch && include_untracked) {\n+\t\tdie(_(\"Can't use --patch and --include-untracked or --all at the same time\"));\n+\t}\n+\n+\tif (!include_untracked) {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct strbuf out = STRBUF_INIT;\n+\n+\t\tcp.git_cmd = 1;\n+\t\targv_array_push(&cp.args, \"ls-files\");\n+\t\targv_array_push(&cp.args, \"--error-unmatch\");\n+\t\tif (argv) {\n+\t\t\targv_array_push(&cp.args, \"--\");\n+\t\t\targv_array_pushv(&cp.args, argv);\n+\t\t}\n+\t\tresult = pipe_command(&cp, NULL, 0, &out, 0, NULL, 0);\n+\t\tif (result != 0) {\n+\t\t\tdie(\"\");\n+\t\t}\n+\t}\n+\n+\trefresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);\n+\tif (check_no_changes(prefix, include_untracked, argv)) {\n+\t\tprintf(_(\"No local changes to save\\n\"));\n+\t\treturn 0;\n+\t}\n+\n+\tif (!reflog_exists(ref_stash)) {\n+\t\tresult = do_clear_stash();\n+\t\tif (result != 0) {\n+\t\t\terror(_(\"Cannot initialize stashs\"));\n+\t\t\treturn result;\n+\t\t}\n+\t}\n+\n+\n+\tdo_create_stash(&info, prefix, message, include_untracked, patch, argv);\n+\tresult = do_store_stash(prefix, info.message, info.w_commit);\n+\n+\tif (result == 0 && !quiet) {\n+\t\tprintf(\"Saved working directory and index state $stash_msg\\n\");\n+\t}\n+\n+\tif (!patch) {\n+\t\tif (argv) {\n+\t\t\tstruct argv_array args;\n+\t\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\t\tstruct child_process cp2 = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf out = STRBUF_INIT;\n+\t\t\targv_array_init(&args);\n+\t\t\targv_array_push(&args, \"reset\");\n+\t\t\targv_array_push(&args, \"--\");\n+\t\t\targv_array_pushv(&args, argv);\n+\t\t\tcmd_reset(args.argc, args.argv, prefix);\n+\n+\n+\t\t\tcp.git_cmd = 1;\n+\t\t\targv_array_push(&cp.args, \"ls-files\");\n+\t\t\targv_array_push(&cp.args, \"-z\");\n+\t\t\targv_array_push(&cp.args, \"--modified\");\n+\t\t\targv_array_push(&cp.args, \"--\");\n+\t\t\targv_array_pushv(&cp.args, argv);\n+\t\t\tpipe_command(&cp, NULL, 0, &out, 0, NULL, 0);\n+\n+\t\t\tcp2.git_cmd = 1;\n+\t\t\targv_array_push(&cp2.args, \"checkout-index\");\n+\t\t\targv_array_push(&cp2.args, \"-z\");\n+\t\t\targv_array_push(&cp2.args, \"--force\");\n+\t\t\targv_array_push(&cp2.args, \"--stdin\");\n+\t\t\tpipe_command(&cp2, out.buf, out.len, NULL, 0, NULL, 0);\n+\n+\t\t\targv_array_init(&args);\n+\t\t\targv_array_push(&args, \"clean\");\n+\t\t\targv_array_push(&args, \"--force\");\n+\t\t\targv_array_push(&args, \"-d\");\n+\t\t\targv_array_push(&args, \"--\");\n+\t\t\targv_array_pushv(&args, argv);\n+\t\t\tcmd_clean(args.argc, args.argv, prefix);\n+\t\t} else {\n+\t\t\tstruct argv_array args;\n+\t\t\targv_array_init(&args);\n+\t\t\targv_array_push(&args, \"reset\");\n+\t\t\targv_array_push(&args, \"--hard\");\n+\t\t\tif (quiet) {\n+\t\t\t\targv_array_push(&args, \"--quiet\");\n+\t\t\t}\n+\t\t\tcmd_reset(args.argc, args.argv, prefix);\n+\t\t}\n+\n+\t\tif (include_untracked) {\n+\t\t\tstruct argv_array args;\n+\t\t\targv_array_init(&args);\n+\t\t\targv_array_push(&args, \"clean\");\n+\t\t\targv_array_push(&args, \"--force\");\n+\t\t\targv_array_push(&args, \"--quiet\");\n+\t\t\targv_array_push(&args, \"-d\");\n+\t\t\tif (include_untracked == 2) {\n+\t\t\t\targv_array_push(&args, \"-x\");\n+\t\t\t}\n+\t\t\tif (argv) {\n+\t\t\t\targv_array_push(&args, \"--\");\n+\t\t\t\targv_array_pushv(&args, argv);\n+\t\t\t}\n+\t\t\tcmd_clean(args.argc, args.argv, prefix);\n+\t\t}\n+\n+\t\tif (keep_index) {\n+\t\t\treset_tree(info.i_tree, 1, 1);\n+\t\t}\n+\t} else {\n+\t\tstruct child_process cp2 = CHILD_PROCESS_INIT;\n+\t\tcp2.git_cmd = 1;\n+\t\targv_array_push(&cp2.args, \"apply\");\n+\t\targv_array_push(&cp2.args, \"-R\");\n+\t\tresult = pipe_command(&cp2, info.patch, strlen(info.patch), NULL, 0, NULL, 0);\n+\t\tif (result != 0) {\n+\t\t\tdie(_(\"Cannot remove worktree changes\"));\n+\t\t}\n+\t\tif (!keep_index) {\n+\t\t\tstruct argv_array args;\n+\t\t\targv_array_init(&args);\n+\t\t\targv_array_push(&args, \"reset\");\n+\t\t\tcmd_reset(args.argc, args.argv, prefix);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+\n+static int push_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *message = NULL;\n+\tint include_untracked = 0;\n+\tint all = 0;\n+\tint patch = 0;\n+\tint keep_index_set = -1;\n+\tint keep_index = 0;\n+\tconst char **args = NULL;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL('u', \"include-untracked\", &include_untracked,\n+\t\t\t N_(\"stash untracked filed\")),\n+\t\tOPT_BOOL('a', \"all\", &all,\n+\t\t\t N_(\"stash ignored untracked files\")),\n+\t\tOPT_BOOL('k', \"keep-index\", &keep_index_set,\n+\t\t\t N_(\"restore the index after applying the stash\")),\n+\t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n+\t\tOPT_STRING('m', \"message\", &message, N_(\"message\"),\n+\t\t\t N_(\"stash commit message\")),\n+\t\tOPT_BOOL('p', \"patch\", &patch,\n+\t\t\t N_(\"edit current diff and apply\")),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_save_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (all) {\n+\t\tinclude_untracked = 2;\n+\t}\n+\n+\tif (keep_index_set != -1) {\n+\t\tkeep_index = keep_index_set;\n+\t} else if (patch) {\n+\t\tkeep_index = 1;\n+\t}\n+\n+\tif (argc != 0) {\n+\t\targs = argv;\n+\t}\n+\n+\treturn do_push_stash(prefix, message, keep_index, include_untracked, patch, args);\n+}\n+\n+static int save_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *message = NULL;\n+\tint include_untracked = 0;\n+\tint all = 0;\n+\tint patch = 0;\n+\tint keep_index_set = -1;\n+\tint keep_index = 0;\n+\tstruct option options[] = {\n+\t\tOPT_BOOL('u', \"include-untracked\", &include_untracked,\n+\t\t\t N_(\"stash untracked filed\")),\n+\t\tOPT_BOOL('a', \"all\", &all,\n+\t\t\t N_(\"stash ignored untracked files\")),\n+\t\tOPT_BOOL('k', \"keep-index\", &keep_index_set,\n+\t\t\t N_(\"restore the index after applying the stash\")),\n+\t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n+\t\tOPT_STRING('m', \"message\", &message, N_(\"message\"),\n+\t\t\t N_(\"stash commit message\")),\n+\t\tOPT_BOOL('p', \"patch\", &patch,\n+\t\t\t N_(\"edit current diff and apply\")),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_save_usage, PARSE_OPT_STOP_AT_NON_OPTION);\n+\n+\tif (all) {\n+\t\tinclude_untracked = 2;\n+\t}\n+\n+\tif (keep_index_set != -1) {\n+\t\tkeep_index = keep_index_set;\n+\t} else if (patch) {\n+\t\tkeep_index = 1;\n+\t}\n+\n+\tif (argc != 0) {\n+\t\tstruct strbuf out = STRBUF_INIT;\n+\t\tint i;\n+\t\tfor (i = 0; i < argc; ++i) {\n+\t\t\tif (i != 0) {\n+\t\t\t\tstrbuf_addf(&out, \" \");\n+\t\t\t}\n+\t\t\tstrbuf_addf(&out, \"%s\", argv[i]);\n+\t\t}\n+\t\tmessage = out.buf;\n+\t}\n+\n+\treturn do_push_stash(prefix, message, keep_index, include_untracked, patch, NULL);\n+}\n+\n+static int do_apply_stash(const char *prefix, const char *commit, int index)\n+{\n+\tstruct object_id h1, h2, btree;\n+\tstruct merge_options o;\n+\tint ret;\n+\tstruct stash_info info;\n+\tunsigned char c_tree[20];\n+\tunsigned char index_tree[20];\n+\tconst struct object_id *bases[1];\n+\tint bases_count = 1;\n+\tstruct commit *result;\n+\tconst char *me = \"git-stash\";\n+\n+\tret = get_stash_info(&info, commit);\n+\n+\tif (!ret) {\n+\t\tprintf(\"invalid\");\n+\t\treturn 1;\n+\t}\n+\n+\tret = refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);\n+\tif (ret != 0) {\n+\t\tprintf(\"invalid2\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = write_cache_as_tree(c_tree, 0, NULL);\n+\tswitch (ret) {\n+\tcase 0:\n+\t\tbreak;\n+\tcase WRITE_TREE_UNREADABLE_INDEX:\n+\t\tdie(\"%s: error reading the index\", me);\n+\t\tbreak;\n+\tcase WRITE_TREE_UNMERGED_INDEX:\n+\t\tdie(\"%s: error building trees\", me);\n+\t\tbreak;\n+\tcase WRITE_TREE_PREFIX_ERROR:\n+\t\tdie(\"%s: prefix %s not found\", me, prefix);\n+\t\tbreak;\n+\t}\n+\n+\n+\tif (index) {\n+\t\tif (memcmp(info.b_tree, info.i_tree, 20) == 0 || memcmp(c_tree, info.i_tree, 20) == 0) {\n+\t\t\tindex = 0;\n+\t\t} else {\n+\t\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\t\tstruct child_process cp2 = CHILD_PROCESS_INIT;\n+\t\t\tstruct strbuf out = STRBUF_INIT;\n+\t\t\tstruct argv_array args;\n+\t\t\tcp.git_cmd = 1;\n+\t\t\targv_array_push(&cp.args, \"diff-tree\");\n+\t\t\targv_array_push(&cp.args, \"--binary\");\n+\t\t\targv_array_pushf(&cp.args, \"%s^2^..%s^2\", sha1_to_hex(info.w_commit), sha1_to_hex(info.w_commit));\n+\t\t\tpipe_command(&cp, NULL, 0, &out, 0, NULL, 0);\n+\n+\t\t\tcp2.git_cmd = 1;\n+\t\t\targv_array_push(&cp2.args, \"apply\");\n+\t\t\targv_array_push(&cp2.args, \"--cached\");\n+\t\t\tpipe_command(&cp2, out.buf, out.len, NULL, 0, NULL, 0);\n+\n+\t\t\tdiscard_cache();\n+\t\t\tread_cache();\n+\t\t\tret = write_cache_as_tree(index_tree, 0, NULL);\n+\n+\t\t\targv_array_init(&args);\n+\t\t\targv_array_push(&args, \"reset\");\n+\t\t\tcmd_reset(args.argc, args.argv, prefix);\n+\t\t}\n+\t}\n+\n+\tif (info.has_u) {\n+\t\tstruct argv_array args;\n+\t\tstruct child_process cp2 = CHILD_PROCESS_INIT;\n+\t\tconst char *index_path = \".git/foocache4\";\n+\n+\t\targv_array_init(&args);\n+\t\targv_array_push(&args, \"read-tree\");\n+\t\targv_array_push(&args, sha1_to_hex(info.u_tree));\n+\t\targv_array_pushf(&args, \"--index-output=%s\", index_path);\n+\n+\n+\t\tcp2.git_cmd = 1;\n+\t\targv_array_push(&cp2.args, \"checkout-index\");\n+\t\targv_array_push(&cp2.args, \"--all\");\n+\t\targv_array_pushf(&cp2.env_array, \"GIT_INDEX_FILE=%s\", index_path);\n+\n+\t\tif (cmd_read_tree(args.argc, args.argv, prefix) ||\n+\t\t\trun_command(&cp2)) {\n+\t\t\tdie(_(\"Could not restore untracked files from stash\"));\n+\t\t}\n+\t\tset_alternate_index_output(\".git/index\");\n+\t}\n+\n+\n+\tinit_merge_options(&o);\n+\n+\to.branch1 = sha1_to_hex(c_tree);\n+\to.branch2 = sha1_to_hex(info.w_tree);\n+\n+\tif (get_oid(o.branch1, &h1))\n+\t\tdie(_(\"could not resolve ref '%s'\"), o.branch1);\n+\tif (get_oid(o.branch2, &h2))\n+\t\tdie(_(\"could not resolve ref '%s'\"), o.branch2);\n+\n+\to.branch1 = \"Updated upstream\";\n+\to.branch2 = \"Stashed changes\";\n+\n+\tif (quiet) {\n+\t\to.verbosity = 0;\n+\t}\n+\n+\tget_oid(sha1_to_hex(info.b_tree), &btree);\n+\tbases[0] = &btree;\n+\n+\tret = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result);\n+\tif (ret != 0) {\n+\t\tstruct argv_array args;\n+\t\targv_array_init(&args);\n+\t\targv_array_push(&args, \"rerere\");\n+\t\tcmd_rerere(args.argc, args.argv, prefix);\n+\n+\t\treturn ret;\n+\t}\n+\n+\tif (index) {\n+\t\tret = reset_tree(index_tree, 0, 0);\n+\t} else {\n+\t\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\t\tstruct child_process cp2 = CHILD_PROCESS_INIT;\n+\t\tstruct strbuf out = STRBUF_INIT;\n+\t\tcp.git_cmd = 1;\n+\t\targv_array_push(&cp.args, \"diff-index\");\n+\t\targv_array_push(&cp.args, \"--cached\");\n+\t\targv_array_push(&cp.args, \"--name-only\");\n+\t\targv_array_push(&cp.args, \"--diff-filter=A\");\n+\t\targv_array_push(&cp.args, sha1_to_hex(c_tree));\n+\t\tret = pipe_command(&cp, NULL, 0, &out, 0, NULL, 0);\n+\n+\t\tret = reset_tree(c_tree, 0, 1);\n+\n+\t\tcp2.git_cmd = 1;\n+\t\targv_array_push(&cp2.args, \"update-index\");\n+\t\targv_array_push(&cp2.args, \"--add\");\n+\t\targv_array_push(&cp2.args, \"--stdin\");\n+\t\tret = pipe_command(&cp2, out.buf, out.len, NULL, 0, NULL, 0);\n+\t}\n+\n+\tif (!quiet) {\n+\t\tstruct argv_array args;\n+\t\targv_array_init(&args);\n+\t\targv_array_push(&args, \"status\");\n+\t\tcmd_status(args.argc, args.argv, prefix);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int apply_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *commit = NULL;\n+\tint index = 0;\n+\tstruct option options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n+\t\tOPT_BOOL(0, \"index\", &index,\n+\t\t\t N_(\"attempt to ininstate the index\")),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_apply_usage, 0);\n+\n+\tif (argc == 1) {\n+\t\tcommit = argv[0];\n+\t}\n+\n+\treturn do_apply_stash(prefix, commit, index);\n+}\n+\n+static int do_drop_stash(const char *prefix, const char *commit)\n+{\n+\tstruct argv_array args;\n+\tint ret;\n+\tstruct stash_info info;\n+\tstruct child_process cp = CHILD_PROCESS_INIT;\n+\n+\tret = get_stash_info(&info, commit);\n+\targv_array_init(&args);\n+\targv_array_push(&args, \"reflog\");\n+\targv_array_push(&args, \"delete\");\n+\targv_array_push(&args, \"--updateref\");\n+\targv_array_push(&args, \"--rewrite\");\n+\targv_array_push(&args, info.REV);\n+\tret = cmd_reflog(args.argc, args.argv, prefix);\n+\tif (ret == 0) {\n+\t\tif (!quiet) {\n+\t\t\tprintf(\"Dropped\\n\");\n+\t\t}\n+\t} else {\n+\t\tdie(\"could not drop\");\n+\t}\n+\n+\tcp.git_cmd = 1;\n+\targv_array_init(&cp.args);\n+\targv_array_push(&cp.args, \"rev-parse\");\n+\targv_array_push(&cp.args, \"--verify\");\n+\targv_array_push(&cp.args, \"--quiet\");\n+\targv_array_push(&cp.args, \"refs/stash@{0}\");\n+\tret = run_command(&cp);\n+\n+\tif (ret != 0) {\n+\t\tdo_clear_stash();\n+\t}\n+\treturn 0;\n+}\n+\n+static int drop_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *commit = NULL;\n+\tstruct option options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_drop_usage, 0);\n+\n+\tif (argc == 1) {\n+\t\tcommit = argv[0];\n+\t}\n+\n+\treturn do_drop_stash(prefix, commit);\n+}\n+\n+static int list_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\n+\tunsigned char w_commit[20];\n+\tstruct object_context unused;\n+\tint ret;\n+\tstruct argv_array args;\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_list_usage, PARSE_OPT_KEEP_UNKNOWN);\n+\n+\tret = get_sha1_with_context(ref_stash, 0, w_commit, &unused);\n+\tif (ret != 0) {\n+\t\treturn 0;\n+\t}\n+\n+\targv_array_init(&args);\n+\targv_array_push(&args, \"log\");\n+\targv_array_push(&args, \"--format=%gd: %gs\");\n+\targv_array_push(&args, \"-g\");\n+\targv_array_push(&args, \"--first-parent\");\n+\targv_array_push(&args, \"-m\");\n+\targv_array_pushv(&args, argv);\n+\targv_array_push(&args, \"refs/stash\");\n+\tret = cmd_log(args.argc, args.argv, prefix);\n+\n+\treturn ret;\n+}\n+\n+static int show_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tstruct argv_array args;\n+\tstruct stash_info info;\n+\tconst char *commit = NULL;\n+\tint ret;\n+\tint numstat = 0;\n+\tint patch = 0;\n+\n+\tstruct option options[] = {\n+\t\tOPT_BOOL(0, \"numstat\", &numstat,\n+\t\t\t N_(\"TODO??\")),\n+\t\tOPT_BOOL('p', \"patch\", &patch,\n+\t\t\t N_(\"TODO??\")),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_show_usage, 0);\n+\n+\tif (argc == 1) {\n+\t\tcommit = argv[0];\n+\t}\n+\tret = get_stash_info(&info, commit);\n+\tif (!ret) {\n+\t\tdie(\"invalid\");\n+\t}\n+\targv_array_init(&args);\n+\targv_array_push(&args, \"diff\");\n+\tif (numstat) {\n+\t\targv_array_push(&args, \"--numstat\");\n+\t} else if (patch) {\n+\t\targv_array_push(&args, \"-p\");\n+\t} else {\n+\t\targv_array_push(&args, \"--stat\");\n+\t}\n+\targv_array_push(&args, sha1_to_hex(info.b_commit));\n+\targv_array_push(&args, sha1_to_hex(info.w_commit));\n+\treturn cmd_diff(args.argc, args.argv, prefix);\n+}\n+\n+static int pop_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tint index = 0;\n+\tint ret;\n+\tconst char *commit = NULL;\n+\tstruct stash_info info;\n+\tstruct option options[] = {\n+\t\tOPT__QUIET(&quiet, N_(\"be quiet, only report errors\")),\n+\t\tOPT_BOOL(0, \"index\", &index,\n+\t\t\t N_(\"attempt to ininstate the index\")),\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_pop_usage, 0);\n+\n+\tif (argc == 1) {\n+\t\tcommit = argv[0];\n+\t}\n+\n+\tget_stash_info(&info, commit);\n+\tif (!info.is_stash_ref) {\n+\t\treturn 1;\n+\t}\n+\n+\tret = do_apply_stash(prefix, commit, index);\n+\tif (ret != 0) {\n+\t\treturn ret;\n+\t}\n+\tret = do_drop_stash(prefix, commit);\n+\treturn ret;\n+}\n+\n+static int branch_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tconst char *commit = NULL, *branch = NULL;\n+\tint ret;\n+\tstruct argv_array args;\n+\tstruct stash_info info;\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\n+\targc = parse_options(argc, argv, prefix, options,\n+\t\t\t\t git_stash_branch_usage, 0);\n+\n+\tif (argc != 0) {\n+\t\tbranch = argv[0];\n+\t\tif (argc == 2) {\n+\t\t\tcommit = argv[1];\n+\t\t}\n+\t}\n+\n+\tret = get_stash_info(&info, commit);\n+\t/* TODO:? if (ret != 0) {\n+\t\treturn ret;\n+\t}*/\n+\n+\targv_array_init(&args);\n+\targv_array_push(&args, \"checkout\");\n+\targv_array_push(&args, \"-b\");\n+\targv_array_push(&args, branch);\n+\targv_array_push(&args, sha1_to_hex(info.b_commit));\n+\tret = cmd_checkout(args.argc, args.argv, prefix);\n+\n+\tret = do_apply_stash(prefix, commit, 1);\n+\tif (info.is_stash_ref) {\n+\t\tret = do_drop_stash(prefix, commit);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+int cmd_stash(int argc, const char **argv, const char *prefix)\n+{\n+\tint result = 0;\n+\n+\tstruct option options[] = {\n+\t\tOPT_END()\n+\t};\n+\n+\tgit_config(git_default_config, NULL);\n+\n+\targc = parse_options(argc, argv, prefix, options, git_stash_usage,\n+\t\tPARSE_OPT_KEEP_UNKNOWN|PARSE_OPT_KEEP_DASHDASH);\n+\n+\tif (argc < 1) {\n+\t\tresult = do_push_stash(NULL, prefix, 0, 0, 0, NULL);\n+\t} else if (!strcmp(argv[0], \"list\"))\n+\t\tresult = list_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"show\"))\n+\t\tresult = show_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"save\"))\n+\t\tresult = save_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"push\"))\n+\t\tresult = push_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"apply\"))\n+\t\tresult = apply_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"clear\"))\n+\t\tresult = clear_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"create\"))\n+\t\tresult = create_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"store\"))\n+\t\tresult = store_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"drop\"))\n+\t\tresult = drop_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"pop\"))\n+\t\tresult = pop_stash(argc, argv, prefix);\n+\telse if (!strcmp(argv[0], \"branch\"))\n+\t\tresult = branch_stash(argc, argv, prefix);\n+\telse {\n+\t\tif (argv[0][0] == '-') {\n+\t\t\tstruct argv_array args;\n+\t\t\targv_array_init(&args);\n+\t\t\targv_array_push(&args, \"push\");\n+\t\t\targv_array_pushv(&args, argv);\n+\t\t\tresult = push_stash(args.argc, args.argv, prefix);\n+\t\t\tif (result == 0) {\n+\t\t\t\tprintf(\"To restore them type \\\"git stash apply\\\"\\n\");\n+\t\t\t}\n+\t\t} else {\n+\t\t\terror(_(\"Unknown subcommand: %s\"), argv[0]);\n+\t\t\tresult = 1;\n+\t\t}\n+\t}\n+\n+\treturn result;\n+}\ndiff --git a/git-stash.sh b/git-stash.sh\ndeleted file mode 100755\nindex 9c70662cc..000000000\n--- a/git-stash.sh\n+++ /dev/null\n@@ -1,731 +0,0 @@\n-#!/bin/sh\n-# Copyright (c) 2007, Nanako Shiraishi\n-\n-dashless=$(basename \"$0\" | sed -e 's/-/ /')\n-USAGE=\"list [<options>]\n-   or: $dashless show [<stash>]\n-   or: $dashless drop [-q|--quiet] [<stash>]\n-   or: $dashless ( pop | apply ) [--index] [-q|--quiet] [<stash>]\n-   or: $dashless branch <branchname> [<stash>]\n-   or: $dashless save [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t      [-u|--include-untracked] [-a|--all] [<message>]\n-   or: $dashless [push [--patch] [-k|--[no-]keep-index] [-q|--quiet]\n-\t\t       [-u|--include-untracked] [-a|--all] [-m <message>]\n-\t\t       [-- <pathspec>...]]\n-   or: $dashless clear\"\n-\n-SUBDIRECTORY_OK=Yes\n-OPTIONS_SPEC=\n-START_DIR=$(pwd)\n-. git-sh-setup\n-require_work_tree\n-cd_to_toplevel\n-\n-TMP=\"$GIT_DIR/.git-stash.$$\"\n-TMPindex=${GIT_INDEX_FILE-\"$(git rev-parse --git-path index)\"}.stash.$$\n-trap 'rm -f \"$TMP-\"* \"$TMPindex\"' 0\n-\n-ref_stash=refs/stash\n-\n-if git config --get-colorbool color.interactive; then\n-       help_color=\"$(git config --get-color color.interactive.help 'red bold')\"\n-       reset_color=\"$(git config --get-color '' reset)\"\n-else\n-       help_color=\n-       reset_color=\n-fi\n-\n-no_changes () {\n-\tgit diff-index --quiet --cached HEAD --ignore-submodules -- \"$@\" &&\n-\tgit diff-files --quiet --ignore-submodules -- \"$@\" &&\n-\t(test -z \"$untracked\" || test -z \"$(untracked_files)\")\n-}\n-\n-untracked_files () {\n-\texcl_opt=--exclude-standard\n-\ttest \"$untracked\" = \"all\" && excl_opt=\n-\tgit ls-files -o -z $excl_opt -- \"$@\"\n-}\n-\n-clear_stash () {\n-\tif test $# != 0\n-\tthen\n-\t\tdie \"$(gettext \"git stash clear with parameters is unimplemented\")\"\n-\tfi\n-\tif current=$(git rev-parse --verify --quiet $ref_stash)\n-\tthen\n-\t\tgit update-ref -d $ref_stash $current\n-\tfi\n-}\n-\n-create_stash () {\n-\tstash_msg=\n-\tuntracked=\n-\twhile test $# != 0\n-\tdo\n-\t\tcase \"$1\" in\n-\t\t-m|--message)\n-\t\t\tshift\n-\t\t\tstash_msg=${1?\"BUG: create_stash () -m requires an argument\"}\n-\t\t\t;;\n-\t\t-u|--include-untracked)\n-\t\t\tshift\n-\t\t\tuntracked=${1?\"BUG: create_stash () -u requires an argument\"}\n-\t\t\t;;\n-\t\t--)\n-\t\t\tshift\n-\t\t\tbreak\n-\t\t\t;;\n-\t\tesac\n-\t\tshift\n-\tdone\n-\n-\tgit update-index -q --refresh\n-\tif no_changes \"$@\"\n-\tthen\n-\t\texit 0\n-\tfi\n-\n-\t# state of the base commit\n-\tif b_commit=$(git rev-parse --verify HEAD)\n-\tthen\n-\t\thead=$(git rev-list --oneline -n 1 HEAD --)\n-\telse\n-\t\tdie \"$(gettext \"You do not have the initial commit yet\")\"\n-\tfi\n-\n-\tif branch=$(git symbolic-ref -q HEAD)\n-\tthen\n-\t\tbranch=${branch#refs/heads/}\n-\telse\n-\t\tbranch='(no branch)'\n-\tfi\n-\tmsg=$(printf '%s: %s' \"$branch\" \"$head\")\n-\n-\t# state of the index\n-\ti_tree=$(git write-tree) &&\n-\ti_commit=$(printf 'index on %s\\n' \"$msg\" |\n-\t\tgit commit-tree $i_tree -p $b_commit) ||\n-\t\tdie \"$(gettext \"Cannot save the current index state\")\"\n-\n-\tif test -n \"$untracked\"\n-\tthen\n-\t\t# Untracked files are stored by themselves in a parentless commit, for\n-\t\t# ease of unpacking later.\n-\t\tu_commit=$(\n-\t\t\tuntracked_files \"$@\" | (\n-\t\t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n-\t\t\t\texport GIT_INDEX_FILE &&\n-\t\t\t\trm -f \"$TMPindex\" &&\n-\t\t\t\tgit update-index -z --add --remove --stdin &&\n-\t\t\t\tu_tree=$(git write-tree) &&\n-\t\t\t\tprintf 'untracked files on %s\\n' \"$msg\" | git commit-tree $u_tree  &&\n-\t\t\t\trm -f \"$TMPindex\"\n-\t\t) ) || die \"$(gettext \"Cannot save the untracked files\")\"\n-\n-\t\tuntracked_commit_option=\"-p $u_commit\";\n-\telse\n-\t\tuntracked_commit_option=\n-\tfi\n-\n-\tif test -z \"$patch_mode\"\n-\tthen\n-\n-\t\t# state of the working tree\n-\t\tw_tree=$( (\n-\t\t\tgit read-tree --index-output=\"$TMPindex\" -m $i_tree &&\n-\t\t\tGIT_INDEX_FILE=\"$TMPindex\" &&\n-\t\t\texport GIT_INDEX_FILE &&\n-\t\t\tgit diff-index --name-only -z HEAD -- \"$@\" >\"$TMP-stagenames\" &&\n-\t\t\tgit update-index -z --add --remove --stdin <\"$TMP-stagenames\" &&\n-\t\t\tgit write-tree &&\n-\t\t\trm -f \"$TMPindex\"\n-\t\t) ) ||\n-\t\t\tdie \"$(gettext \"Cannot save the current worktree state\")\"\n-\n-\telse\n-\n-\t\trm -f \"$TMP-index\" &&\n-\t\tGIT_INDEX_FILE=\"$TMP-index\" git read-tree HEAD &&\n-\n-\t\t# find out what the user wants\n-\t\tGIT_INDEX_FILE=\"$TMP-index\" \\\n-\t\t\tgit add--interactive --patch=stash -- \"$@\" &&\n-\n-\t\t# state of the working tree\n-\t\tw_tree=$(GIT_INDEX_FILE=\"$TMP-index\" git write-tree) ||\n-\t\tdie \"$(gettext \"Cannot save the current worktree state\")\"\n-\n-\t\tgit diff-tree -p HEAD $w_tree -- >\"$TMP-patch\" &&\n-\t\ttest -s \"$TMP-patch\" ||\n-\t\tdie \"$(gettext \"No changes selected\")\"\n-\n-\t\trm -f \"$TMP-index\" ||\n-\t\tdie \"$(gettext \"Cannot remove temporary index (can't happen)\")\"\n-\n-\tfi\n-\n-\t# create the stash\n-\tif test -z \"$stash_msg\"\n-\tthen\n-\t\tstash_msg=$(printf 'WIP on %s' \"$msg\")\n-\telse\n-\t\tstash_msg=$(printf 'On %s: %s' \"$branch\" \"$stash_msg\")\n-\tfi\n-\tw_commit=$(printf '%s\\n' \"$stash_msg\" |\n-\tgit commit-tree $w_tree -p $b_commit -p $i_commit $untracked_commit_option) ||\n-\tdie \"$(gettext \"Cannot record working tree state\")\"\n-}\n-\n-store_stash () {\n-\twhile test $# != 0\n-\tdo\n-\t\tcase \"$1\" in\n-\t\t-m|--message)\n-\t\t\tshift\n-\t\t\tstash_msg=\"$1\"\n-\t\t\t;;\n-\t\t-q|--quiet)\n-\t\t\tquiet=t\n-\t\t\t;;\n-\t\t*)\n-\t\t\tbreak\n-\t\t\t;;\n-\t\tesac\n-\t\tshift\n-\tdone\n-\ttest $# = 1 ||\n-\tdie \"$(eval_gettext \"\\\"$dashless store\\\" requires one <commit> argument\")\"\n-\n-\tw_commit=\"$1\"\n-\tif test -z \"$stash_msg\"\n-\tthen\n-\t\tstash_msg=\"Created via \\\"git stash store\\\".\"\n-\tfi\n-\n-\tgit update-ref --create-reflog -m \"$stash_msg\" $ref_stash $w_commit\n-\tret=$?\n-\ttest $ret != 0 && test -z \"$quiet\" &&\n-\tdie \"$(eval_gettext \"Cannot update \\$ref_stash with \\$w_commit\")\"\n-\treturn $ret\n-}\n-\n-push_stash () {\n-\tkeep_index=\n-\tpatch_mode=\n-\tuntracked=\n-\tstash_msg=\n-\twhile test $# != 0\n-\tdo\n-\t\tcase \"$1\" in\n-\t\t-k|--keep-index)\n-\t\t\tkeep_index=t\n-\t\t\t;;\n-\t\t--no-keep-index)\n-\t\t\tkeep_index=n\n-\t\t\t;;\n-\t\t-p|--patch)\n-\t\t\tpatch_mode=t\n-\t\t\t# only default to keep if we don't already have an override\n-\t\t\ttest -z \"$keep_index\" && keep_index=t\n-\t\t\t;;\n-\t\t-q|--quiet)\n-\t\t\tGIT_QUIET=t\n-\t\t\t;;\n-\t\t-u|--include-untracked)\n-\t\t\tuntracked=untracked\n-\t\t\t;;\n-\t\t-a|--all)\n-\t\t\tuntracked=all\n-\t\t\t;;\n-\t\t-m|--message)\n-\t\t\tshift\n-\t\t\ttest -z ${1+x} && usage\n-\t\t\tstash_msg=$1\n-\t\t\t;;\n-\t\t--help)\n-\t\t\tshow_help\n-\t\t\t;;\n-\t\t--)\n-\t\t\tshift\n-\t\t\tbreak\n-\t\t\t;;\n-\t\t-*)\n-\t\t\toption=\"$1\"\n-\t\t\t# TRANSLATORS: $option is an invalid option, like\n-\t\t\t# `--blah-blah'. The 7 spaces at the beginning of the\n-\t\t\t# second line correspond to \"error: \". So you should line\n-\t\t\t# up the second line with however many characters the\n-\t\t\t# translation of \"error: \" takes in your language. E.g. in\n-\t\t\t# English this is:\n-\t\t\t#\n-\t\t\t#    $ git stash save --blah-blah 2>&1 | head -n 2\n-\t\t\t#    error: unknown option for 'stash save': --blah-blah\n-\t\t\t#           To provide a message, use git stash save -- '--blah-blah'\n-\t\t\teval_gettextln \"error: unknown option for 'stash save': \\$option\n-       To provide a message, use git stash save -- '\\$option'\"\n-\t\t\tusage\n-\t\t\t;;\n-\t\t*)\n-\t\t\tbreak\n-\t\t\t;;\n-\t\tesac\n-\t\tshift\n-\tdone\n-\n-\tif test -n \"$patch_mode\" && test -n \"$untracked\"\n-\tthen\n-\t\tdie \"$(gettext \"Can't use --patch and --include-untracked or --all at the same time\")\"\n-\tfi\n-\n-\ttest -n \"$untracked\" || git ls-files --error-unmatch -- \"$@\" >/dev/null || exit 1\n-\n-\tgit update-index -q --refresh\n-\tif no_changes \"$@\"\n-\tthen\n-\t\tsay \"$(gettext \"No local changes to save\")\"\n-\t\texit 0\n-\tfi\n-\n-\tgit reflog exists $ref_stash ||\n-\t\tclear_stash || die \"$(gettext \"Cannot initialize stash\")\"\n-\n-\tcreate_stash -m \"$stash_msg\" -u \"$untracked\" -- \"$@\"\n-\tstore_stash -m \"$stash_msg\" -q $w_commit ||\n-\tdie \"$(gettext \"Cannot save the current status\")\"\n-\tsay \"$(eval_gettext \"Saved working directory and index state \\$stash_msg\")\"\n-\n-\tif test -z \"$patch_mode\"\n-\tthen\n-\t\tif test $# != 0\n-\t\tthen\n-\t\t\tgit reset ${GIT_QUIET:+-q} -- \"$@\"\n-\t\t\tgit ls-files -z --modified -- \"$@\" |\n-\t\t\tgit checkout-index -z --force --stdin\n-\t\t\tgit clean --force ${GIT_QUIET:+-q} -d -- \"$@\"\n-\t\telse\n-\t\t\tgit reset --hard ${GIT_QUIET:+-q}\n-\t\tfi\n-\t\ttest \"$untracked\" = \"all\" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=\n-\t\tif test -n \"$untracked\"\n-\t\tthen\n-\t\t\tgit clean --force --quiet -d $CLEAN_X_OPTION -- \"$@\"\n-\t\tfi\n-\n-\t\tif test \"$keep_index\" = \"t\" && test -n \"$i_tree\"\n-\t\tthen\n-\t\t\tgit read-tree --reset -u $i_tree\n-\t\tfi\n-\telse\n-\t\tgit apply -R < \"$TMP-patch\" ||\n-\t\tdie \"$(gettext \"Cannot remove worktree changes\")\"\n-\n-\t\tif test \"$keep_index\" != \"t\"\n-\t\tthen\n-\t\t\tgit reset\n-\t\tfi\n-\tfi\n-}\n-\n-save_stash () {\n-\tpush_options=\n-\twhile test $# != 0\n-\tdo\n-\t\tcase \"$1\" in\n-\t\t--)\n-\t\t\tshift\n-\t\t\tbreak\n-\t\t\t;;\n-\t\t-*)\n-\t\t\t# pass all options through to push_stash\n-\t\t\tpush_options=\"$push_options $1\"\n-\t\t\t;;\n-\t\t*)\n-\t\t\tbreak\n-\t\t\t;;\n-\t\tesac\n-\t\tshift\n-\tdone\n-\n-\tstash_msg=\"$*\"\n-\n-\tif test -z \"$stash_msg\"\n-\tthen\n-\t\tpush_stash $push_options\n-\telse\n-\t\tpush_stash $push_options -m \"$stash_msg\"\n-\tfi\n-}\n-\n-have_stash () {\n-\tgit rev-parse --verify --quiet $ref_stash >/dev/null\n-}\n-\n-list_stash () {\n-\thave_stash || return 0\n-\tgit log --format=\"%gd: %gs\" -g --first-parent -m \"$@\" $ref_stash --\n-}\n-\n-show_stash () {\n-\tALLOW_UNKNOWN_FLAGS=t\n-\tassert_stash_like \"$@\"\n-\n-\tif test -z \"$FLAGS\"\n-\tthen\n-\t\tif test \"$(git config --bool stash.showStat || echo true)\" = \"true\"\n-\t\tthen\n-\t\t\tFLAGS=--stat\n-\t\tfi\n-\n-\t\tif test \"$(git config --bool stash.showPatch || echo false)\" = \"true\"\n-\t\tthen\n-\t\t\tFLAGS=${FLAGS}${FLAGS:+ }-p\n-\t\tfi\n-\n-\t\tif test -z \"$FLAGS\"\n-\t\tthen\n-\t\t\treturn 0\n-\t\tfi\n-\tfi\n-\n-\tgit diff ${FLAGS} $b_commit $w_commit\n-}\n-\n-show_help () {\n-\texec git help stash\n-\texit 1\n-}\n-\n-#\n-# Parses the remaining options looking for flags and\n-# at most one revision defaulting to ${ref_stash}@{0}\n-# if none found.\n-#\n-# Derives related tree and commit objects from the\n-# revision, if one is found.\n-#\n-# stash records the work tree, and is a merge between the\n-# base commit (first parent) and the index tree (second parent).\n-#\n-#   REV is set to the symbolic version of the specified stash-like commit\n-#   IS_STASH_LIKE is non-blank if ${REV} looks like a stash\n-#   IS_STASH_REF is non-blank if the ${REV} looks like a stash ref\n-#   s is set to the SHA1 of the stash commit\n-#   w_commit is set to the commit containing the working tree\n-#   b_commit is set to the base commit\n-#   i_commit is set to the commit containing the index tree\n-#   u_commit is set to the commit containing the untracked files tree\n-#   w_tree is set to the working tree\n-#   b_tree is set to the base tree\n-#   i_tree is set to the index tree\n-#   u_tree is set to the untracked files tree\n-#\n-#   GIT_QUIET is set to t if -q is specified\n-#   INDEX_OPTION is set to --index if --index is specified.\n-#   FLAGS is set to the remaining flags (if allowed)\n-#\n-# dies if:\n-#   * too many revisions specified\n-#   * no revision is specified and there is no stash stack\n-#   * a revision is specified which cannot be resolve to a SHA1\n-#   * a non-existent stash reference is specified\n-#   * unknown flags were set and ALLOW_UNKNOWN_FLAGS is not \"t\"\n-#\n-\n-parse_flags_and_rev()\n-{\n-\ttest \"$PARSE_CACHE\" = \"$*\" && return 0 # optimisation\n-\tPARSE_CACHE=\"$*\"\n-\n-\tIS_STASH_LIKE=\n-\tIS_STASH_REF=\n-\tINDEX_OPTION=\n-\ts=\n-\tw_commit=\n-\tb_commit=\n-\ti_commit=\n-\tu_commit=\n-\tw_tree=\n-\tb_tree=\n-\ti_tree=\n-\tu_tree=\n-\n-\tFLAGS=\n-\tREV=\n-\tfor opt\n-\tdo\n-\t\tcase \"$opt\" in\n-\t\t\t-q|--quiet)\n-\t\t\t\tGIT_QUIET=-t\n-\t\t\t;;\n-\t\t\t--index)\n-\t\t\t\tINDEX_OPTION=--index\n-\t\t\t;;\n-\t\t\t--help)\n-\t\t\t\tshow_help\n-\t\t\t;;\n-\t\t\t-*)\n-\t\t\t\ttest \"$ALLOW_UNKNOWN_FLAGS\" = t ||\n-\t\t\t\t\tdie \"$(eval_gettext \"unknown option: \\$opt\")\"\n-\t\t\t\tFLAGS=\"${FLAGS}${FLAGS:+ }$opt\"\n-\t\t\t;;\n-\t\t\t*)\n-\t\t\t\tREV=\"${REV}${REV:+ }'$opt'\"\n-\t\t\t;;\n-\t\tesac\n-\tdone\n-\n-\teval set -- $REV\n-\n-\tcase $# in\n-\t\t0)\n-\t\t\thave_stash || die \"$(gettext \"No stash found.\")\"\n-\t\t\tset -- ${ref_stash}@{0}\n-\t\t;;\n-\t\t1)\n-\t\t\t:\n-\t\t;;\n-\t\t*)\n-\t\t\tdie \"$(eval_gettext \"Too many revisions specified: \\$REV\")\"\n-\t\t;;\n-\tesac\n-\n-\tcase \"$1\" in\n-\t\t*[!0-9]*)\n-\t\t\t:\n-\t\t;;\n-\t\t*)\n-\t\t\tset -- \"${ref_stash}@{$1}\"\n-\t\t;;\n-\tesac\n-\n-\tREV=$(git rev-parse --symbolic --verify --quiet \"$1\") || {\n-\t\treference=\"$1\"\n-\t\tdie \"$(eval_gettext \"\\$reference is not a valid reference\")\"\n-\t}\n-\n-\ti_commit=$(git rev-parse --verify --quiet \"$REV^2\") &&\n-\tset -- $(git rev-parse \"$REV\" \"$REV^1\" \"$REV:\" \"$REV^1:\" \"$REV^2:\" 2>/dev/null) &&\n-\ts=$1 &&\n-\tw_commit=$1 &&\n-\tb_commit=$2 &&\n-\tw_tree=$3 &&\n-\tb_tree=$4 &&\n-\ti_tree=$5 &&\n-\tIS_STASH_LIKE=t &&\n-\ttest \"$ref_stash\" = \"$(git rev-parse --symbolic-full-name \"${REV%@*}\")\" &&\n-\tIS_STASH_REF=t\n-\n-\tu_commit=$(git rev-parse --verify --quiet \"$REV^3\") &&\n-\tu_tree=$(git rev-parse \"$REV^3:\" 2>/dev/null)\n-}\n-\n-is_stash_like()\n-{\n-\tparse_flags_and_rev \"$@\"\n-\ttest -n \"$IS_STASH_LIKE\"\n-}\n-\n-assert_stash_like() {\n-\tis_stash_like \"$@\" || {\n-\t\targs=\"$*\"\n-\t\tdie \"$(eval_gettext \"'\\$args' is not a stash-like commit\")\"\n-\t}\n-}\n-\n-is_stash_ref() {\n-\tis_stash_like \"$@\" && test -n \"$IS_STASH_REF\"\n-}\n-\n-assert_stash_ref() {\n-\tis_stash_ref \"$@\" || {\n-\t\targs=\"$*\"\n-\t\tdie \"$(eval_gettext \"'\\$args' is not a stash reference\")\"\n-\t}\n-}\n-\n-apply_stash () {\n-\n-\tassert_stash_like \"$@\"\n-\n-\tgit update-index -q --refresh || die \"$(gettext \"unable to refresh index\")\"\n-\n-\t# current index state\n-\tc_tree=$(git write-tree) ||\n-\t\tdie \"$(gettext \"Cannot apply a stash in the middle of a merge\")\"\n-\n-\tunstashed_index_tree=\n-\tif test -n \"$INDEX_OPTION\" && test \"$b_tree\" != \"$i_tree\" &&\n-\t\t\ttest \"$c_tree\" != \"$i_tree\"\n-\tthen\n-\t\tgit diff-tree --binary $s^2^..$s^2 | git apply --cached\n-\t\ttest $? -ne 0 &&\n-\t\t\tdie \"$(gettext \"Conflicts in index. Try without --index.\")\"\n-\t\tunstashed_index_tree=$(git write-tree) ||\n-\t\t\tdie \"$(gettext \"Could not save index tree\")\"\n-\t\tgit reset\n-\tfi\n-\n-\tif test -n \"$u_tree\"\n-\tthen\n-\t\tGIT_INDEX_FILE=\"$TMPindex\" git-read-tree \"$u_tree\" &&\n-\t\tGIT_INDEX_FILE=\"$TMPindex\" git checkout-index --all &&\n-\t\trm -f \"$TMPindex\" ||\n-\t\tdie \"$(gettext \"Could not restore untracked files from stash\")\"\n-\tfi\n-\n-\teval \"\n-\t\tGITHEAD_$w_tree='Stashed changes' &&\n-\t\tGITHEAD_$c_tree='Updated upstream' &&\n-\t\tGITHEAD_$b_tree='Version stash was based on' &&\n-\t\texport GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree\n-\t\"\n-\n-\tif test -n \"$GIT_QUIET\"\n-\tthen\n-\t\tGIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY\n-\tfi\n-\tif git merge-recursive $b_tree -- $c_tree $w_tree\n-\tthen\n-\t\t# No conflict\n-\t\tif test -n \"$unstashed_index_tree\"\n-\t\tthen\n-\t\t\tgit read-tree \"$unstashed_index_tree\"\n-\t\telse\n-\t\t\ta=\"$TMP-added\" &&\n-\t\t\tgit diff-index --cached --name-only --diff-filter=A $c_tree >\"$a\" &&\n-\t\t\tgit read-tree --reset $c_tree &&\n-\t\t\tgit update-index --add --stdin <\"$a\" ||\n-\t\t\t\tdie \"$(gettext \"Cannot unstage modified files\")\"\n-\t\t\trm -f \"$a\"\n-\t\tfi\n-\t\tsquelch=\n-\t\tif test -n \"$GIT_QUIET\"\n-\t\tthen\n-\t\t\tsquelch='>/dev/null 2>&1'\n-\t\tfi\n-\t\t(cd \"$START_DIR\" && eval \"git status $squelch\") || :\n-\telse\n-\t\t# Merge conflict; keep the exit status from merge-recursive\n-\t\tstatus=$?\n-\t\tgit rerere\n-\t\tif test -n \"$INDEX_OPTION\"\n-\t\tthen\n-\t\t\tgettextln \"Index was not unstashed.\" >&2\n-\t\tfi\n-\t\texit $status\n-\tfi\n-}\n-\n-pop_stash() {\n-\tassert_stash_ref \"$@\"\n-\n-\tif apply_stash \"$@\"\n-\tthen\n-\t\tdrop_stash \"$@\"\n-\telse\n-\t\tstatus=$?\n-\t\tsay \"$(gettext \"The stash is kept in case you need it again.\")\"\n-\t\texit $status\n-\tfi\n-}\n-\n-drop_stash () {\n-\tassert_stash_ref \"$@\"\n-\n-\tgit reflog delete --updateref --rewrite \"${REV}\" &&\n-\t\tsay \"$(eval_gettext \"Dropped \\${REV} (\\$s)\")\" ||\n-\t\tdie \"$(eval_gettext \"\\${REV}: Could not drop stash entry\")\"\n-\n-\t# clear_stash if we just dropped the last stash entry\n-\tgit rev-parse --verify --quiet \"$ref_stash@{0}\" >/dev/null ||\n-\tclear_stash\n-}\n-\n-apply_to_branch () {\n-\ttest -n \"$1\" || die \"$(gettext \"No branch name specified\")\"\n-\tbranch=$1\n-\tshift 1\n-\n-\tset -- --index \"$@\"\n-\tassert_stash_like \"$@\"\n-\n-\tgit checkout -b $branch $REV^ &&\n-\tapply_stash \"$@\" && {\n-\t\ttest -z \"$IS_STASH_REF\" || drop_stash \"$@\"\n-\t}\n-}\n-\n-test \"$1\" = \"-p\" && set \"push\" \"$@\"\n-\n-PARSE_CACHE='--not-parsed'\n-# The default command is \"push\" if nothing but options are given\n-seen_non_option=\n-for opt\n-do\n-\tcase \"$opt\" in\n-\t--) break ;;\n-\t-*) ;;\n-\t*) seen_non_option=t; break ;;\n-\tesac\n-done\n-\n-test -n \"$seen_non_option\" || set \"push\" \"$@\"\n-\n-# Main command set\n-case \"$1\" in\n-list)\n-\tshift\n-\tlist_stash \"$@\"\n-\t;;\n-show)\n-\tshift\n-\tshow_stash \"$@\"\n-\t;;\n-save)\n-\tshift\n-\tsave_stash \"$@\"\n-\t;;\n-push)\n-\tshift\n-\tpush_stash \"$@\"\n-\t;;\n-apply)\n-\tshift\n-\tapply_stash \"$@\"\n-\t;;\n-clear)\n-\tshift\n-\tclear_stash \"$@\"\n-\t;;\n-create)\n-\tshift\n-\tcreate_stash -m \"$*\" && echo \"$w_commit\"\n-\t;;\n-store)\n-\tshift\n-\tstore_stash \"$@\"\n-\t;;\n-drop)\n-\tshift\n-\tdrop_stash \"$@\"\n-\t;;\n-pop)\n-\tshift\n-\tpop_stash \"$@\"\n-\t;;\n-branch)\n-\tshift\n-\tapply_to_branch \"$@\"\n-\t;;\n-*)\n-\tcase $# in\n-\t0)\n-\t\tpush_stash &&\n-\t\tsay \"$(gettext \"(To restore them type \\\"git stash apply\\\")\")\"\n-\t\t;;\n-\t*)\n-\t\tusage\n-\tesac\n-\t;;\n-esac\ndiff --git a/git.c b/git.c\nindex 33f52acbc..2b8a69a42 100644\n--- a/git.c\n+++ b/git.c\n@@ -493,6 +493,7 @@ static struct cmd_struct commands[] = {\n \t{ \"show-branch\", cmd_show_branch, RUN_SETUP },\n \t{ \"show-ref\", cmd_show_ref, RUN_SETUP },\n \t{ \"stage\", cmd_add, RUN_SETUP | NEED_WORK_TREE },\n+\t{ \"stash\", cmd_stash, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"status\", cmd_status, RUN_SETUP | NEED_WORK_TREE },\n \t{ \"stripspace\", cmd_stripspace },\n \t{ \"submodule--helper\", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX},\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 62decd51c..4502e649d 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2145,9 +2145,8 @@ int merge_recursive_generic(struct merge_options *o,\n \tif (clean < 0)\n \t\treturn clean;\n \n-\tif (active_cache_changed &&\n-\t    write_locked_index(&the_index, lock, COMMIT_LOCK))\n-\t\treturn err(o, _(\"Unable to write index.\"));\n+\t    if (write_locked_index(&the_index, lock, COMMIT_LOCK))\n+\t\t\treturn err(o, _(\"Unable to write index.\"));\n \n \treturn clean ? 0 : 1;\n }\n-- \n2.12.0\n\n"}]}