03511f466b3d9ee2d12b09ce0266a0f1de6517b0
   1#include "builtin.h"
   2#include "config.h"
   3#include "parse-options.h"
   4#include "refs.h"
   5#include "lockfile.h"
   6#include "cache-tree.h"
   7#include "unpack-trees.h"
   8#include "merge-recursive.h"
   9#include "argv-array.h"
  10#include "run-command.h"
  11#include "dir.h"
  12#include "rerere.h"
  13
  14static const char * const git_stash_helper_usage[] = {
  15        N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
  16        NULL
  17};
  18
  19static const char * const git_stash_helper_apply_usage[] = {
  20        N_("git stash--helper apply [--index] [-q|--quiet] [<stash>]"),
  21        NULL
  22};
  23
  24static const char *ref_stash = "refs/stash";
  25static struct strbuf stash_index_path = STRBUF_INIT;
  26
  27/*
  28 * w_commit is set to the commit containing the working tree
  29 * b_commit is set to the base commit
  30 * i_commit is set to the commit containing the index tree
  31 * u_commit is set to the commit containing the untracked files tree
  32 * w_tree is set to the working tree
  33 * b_tree is set to the base tree
  34 * i_tree is set to the index tree
  35 * u_tree is set to the untracked files tree
  36 */
  37struct stash_info {
  38        struct object_id w_commit;
  39        struct object_id b_commit;
  40        struct object_id i_commit;
  41        struct object_id u_commit;
  42        struct object_id w_tree;
  43        struct object_id b_tree;
  44        struct object_id i_tree;
  45        struct object_id u_tree;
  46        struct strbuf revision;
  47        int is_stash_ref;
  48        int has_u;
  49};
  50
  51static void free_stash_info(struct stash_info *info)
  52{
  53        strbuf_release(&info->revision);
  54}
  55
  56static void assert_stash_like(struct stash_info *info, const char *revision)
  57{
  58        if (get_oidf(&info->b_commit, "%s^1", revision) ||
  59            get_oidf(&info->w_tree, "%s:", revision) ||
  60            get_oidf(&info->b_tree, "%s^1:", revision) ||
  61            get_oidf(&info->i_tree, "%s^2:", revision))
  62                die(_("'%s' is not a stash-like commit"), revision);
  63}
  64
  65static int get_stash_info(struct stash_info *info, int argc, const char **argv)
  66{
  67        int ret;
  68        char *end_of_rev;
  69        char *expanded_ref;
  70        const char *revision;
  71        const char *commit = NULL;
  72        struct object_id dummy;
  73        struct strbuf symbolic = STRBUF_INIT;
  74
  75        if (argc > 1) {
  76                int i;
  77                struct strbuf refs_msg = STRBUF_INIT;
  78
  79                for (i = 0; i < argc; i++)
  80                        strbuf_addf(&refs_msg, " '%s'", argv[i]);
  81
  82                fprintf_ln(stderr, _("Too many revisions specified:%s"),
  83                           refs_msg.buf);
  84                strbuf_release(&refs_msg);
  85
  86                return -1;
  87        }
  88
  89        if (argc == 1)
  90                commit = argv[0];
  91
  92        strbuf_init(&info->revision, 0);
  93        if (!commit) {
  94                if (!ref_exists(ref_stash)) {
  95                        free_stash_info(info);
  96                        fprintf_ln(stderr, _("No stash entries found."));
  97                        return -1;
  98                }
  99
 100                strbuf_addf(&info->revision, "%s@{0}", ref_stash);
 101        } else if (strspn(commit, "0123456789") == strlen(commit)) {
 102                strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit);
 103        } else {
 104                strbuf_addstr(&info->revision, commit);
 105        }
 106
 107        revision = info->revision.buf;
 108
 109        if (get_oid(revision, &info->w_commit)) {
 110                error(_("%s is not a valid reference"), revision);
 111                free_stash_info(info);
 112                return -1;
 113        }
 114
 115        assert_stash_like(info, revision);
 116
 117        info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision);
 118
 119        end_of_rev = strchrnul(revision, '@');
 120        strbuf_add(&symbolic, revision, end_of_rev - revision);
 121
 122        ret = dwim_ref(symbolic.buf, symbolic.len, &dummy, &expanded_ref);
 123        strbuf_release(&symbolic);
 124        switch (ret) {
 125        case 0: /* Not found, but valid ref */
 126                info->is_stash_ref = 0;
 127                break;
 128        case 1:
 129                info->is_stash_ref = !strcmp(expanded_ref, ref_stash);
 130                break;
 131        default: /* Invalid or ambiguous */
 132                free_stash_info(info);
 133        }
 134
 135        free(expanded_ref);
 136        return !(ret == 0 || ret == 1);
 137}
 138
 139static int reset_tree(struct object_id *i_tree, int update, int reset)
 140{
 141        int nr_trees = 1;
 142        struct unpack_trees_options opts;
 143        struct tree_desc t[MAX_UNPACK_TREES];
 144        struct tree *tree;
 145        struct lock_file lock_file = LOCK_INIT;
 146
 147        read_cache_preload(NULL);
 148        if (refresh_cache(REFRESH_QUIET))
 149                return -1;
 150
 151        hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
 152
 153        memset(&opts, 0, sizeof(opts));
 154
 155        tree = parse_tree_indirect(i_tree);
 156        if (parse_tree(tree))
 157                return -1;
 158
 159        init_tree_desc(t, tree->buffer, tree->size);
 160
 161        opts.head_idx = 1;
 162        opts.src_index = &the_index;
 163        opts.dst_index = &the_index;
 164        opts.merge = 1;
 165        opts.reset = reset;
 166        opts.update = update;
 167        opts.fn = oneway_merge;
 168
 169        if (unpack_trees(nr_trees, t, &opts))
 170                return -1;
 171
 172        if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
 173                return error(_("unable to write new index file"));
 174
 175        return 0;
 176}
 177
 178static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit)
 179{
 180        struct child_process cp = CHILD_PROCESS_INIT;
 181        const char *w_commit_hex = oid_to_hex(w_commit);
 182
 183        /*
 184         * Diff-tree would not be very hard to replace with a native function,
 185         * however it should be done together with apply_cached.
 186         */
 187        cp.git_cmd = 1;
 188        argv_array_pushl(&cp.args, "diff-tree", "--binary", NULL);
 189        argv_array_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
 190
 191        return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
 192}
 193
 194static int apply_cached(struct strbuf *out)
 195{
 196        struct child_process cp = CHILD_PROCESS_INIT;
 197
 198        /*
 199         * Apply currently only reads either from stdin or a file, thus
 200         * apply_all_patches would have to be updated to optionally take a
 201         * buffer.
 202         */
 203        cp.git_cmd = 1;
 204        argv_array_pushl(&cp.args, "apply", "--cached", NULL);
 205        return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
 206}
 207
 208static int reset_head(void)
 209{
 210        struct child_process cp = CHILD_PROCESS_INIT;
 211
 212        /*
 213         * Reset is overall quite simple, however there is no current public
 214         * API for resetting.
 215         */
 216        cp.git_cmd = 1;
 217        argv_array_push(&cp.args, "reset");
 218
 219        return run_command(&cp);
 220}
 221
 222static int get_newly_staged(struct strbuf *out, struct object_id *c_tree)
 223{
 224        struct child_process cp = CHILD_PROCESS_INIT;
 225        const char *c_tree_hex = oid_to_hex(c_tree);
 226
 227        /*
 228         * diff-index is very similar to diff-tree above, and should be
 229         * converted together with update_index.
 230         */
 231        cp.git_cmd = 1;
 232        argv_array_pushl(&cp.args, "diff-index", "--cached", "--name-only",
 233                         "--diff-filter=A", NULL);
 234        argv_array_push(&cp.args, c_tree_hex);
 235        return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
 236}
 237
 238static int update_index(struct strbuf *out)
 239{
 240        struct child_process cp = CHILD_PROCESS_INIT;
 241
 242        /*
 243         * Update-index is very complicated and may need to have a public
 244         * function exposed in order to remove this forking.
 245         */
 246        cp.git_cmd = 1;
 247        argv_array_pushl(&cp.args, "update-index", "--add", "--stdin", NULL);
 248        return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
 249}
 250
 251static int restore_untracked(struct object_id *u_tree)
 252{
 253        int res;
 254        struct child_process cp = CHILD_PROCESS_INIT;
 255
 256        /*
 257         * We need to run restore files from a given index, but without
 258         * affecting the current index, so we use GIT_INDEX_FILE with
 259         * run_command to fork processes that will not interfere.
 260         */
 261        cp.git_cmd = 1;
 262        argv_array_push(&cp.args, "read-tree");
 263        argv_array_push(&cp.args, oid_to_hex(u_tree));
 264        argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
 265                         stash_index_path.buf);
 266        if (run_command(&cp)) {
 267                remove_path(stash_index_path.buf);
 268                return -1;
 269        }
 270
 271        child_process_init(&cp);
 272        cp.git_cmd = 1;
 273        argv_array_pushl(&cp.args, "checkout-index", "--all", NULL);
 274        argv_array_pushf(&cp.env_array, "GIT_INDEX_FILE=%s",
 275                         stash_index_path.buf);
 276
 277        res = run_command(&cp);
 278        remove_path(stash_index_path.buf);
 279        return res;
 280}
 281
 282static int do_apply_stash(const char *prefix, struct stash_info *info,
 283                          int index, int quiet)
 284{
 285        int ret;
 286        int has_index = index;
 287        struct merge_options o;
 288        struct object_id c_tree;
 289        struct object_id index_tree;
 290        struct commit *result;
 291        const struct object_id *bases[1];
 292
 293        read_cache_preload(NULL);
 294        if (refresh_cache(REFRESH_QUIET))
 295                return -1;
 296
 297        if (write_cache_as_tree(&c_tree, 0, NULL))
 298                return error(_("cannot apply a stash in the middle of a merge"));
 299
 300        if (index) {
 301                if (oideq(&info->b_tree, &info->i_tree) ||
 302                    oideq(&c_tree, &info->i_tree)) {
 303                        has_index = 0;
 304                } else {
 305                        struct strbuf out = STRBUF_INIT;
 306
 307                        if (diff_tree_binary(&out, &info->w_commit)) {
 308                                strbuf_release(&out);
 309                                return error(_("could not generate diff %s^!."),
 310                                             oid_to_hex(&info->w_commit));
 311                        }
 312
 313                        ret = apply_cached(&out);
 314                        strbuf_release(&out);
 315                        if (ret)
 316                                return error(_("conflicts in index."
 317                                               "Try without --index."));
 318
 319                        discard_cache();
 320                        read_cache();
 321                        if (write_cache_as_tree(&index_tree, 0, NULL))
 322                                return error(_("could not save index tree"));
 323
 324                        reset_head();
 325                }
 326        }
 327
 328        if (info->has_u && restore_untracked(&info->u_tree))
 329                return error(_("could not restore untracked files from stash"));
 330
 331        init_merge_options(&o);
 332
 333        o.branch1 = "Updated upstream";
 334        o.branch2 = "Stashed changes";
 335
 336        if (oideq(&info->b_tree, &c_tree))
 337                o.branch1 = "Version stash was based on";
 338
 339        if (quiet)
 340                o.verbosity = 0;
 341
 342        if (o.verbosity >= 3)
 343                printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
 344
 345        bases[0] = &info->b_tree;
 346
 347        ret = merge_recursive_generic(&o, &c_tree, &info->w_tree, 1, bases,
 348                                      &result);
 349        if (ret) {
 350                rerere(0);
 351
 352                if (index)
 353                        fprintf_ln(stderr, _("Index was not unstashed."));
 354
 355                return ret;
 356        }
 357
 358        if (has_index) {
 359                if (reset_tree(&index_tree, 0, 0))
 360                        return -1;
 361        } else {
 362                struct strbuf out = STRBUF_INIT;
 363
 364                if (get_newly_staged(&out, &c_tree)) {
 365                        strbuf_release(&out);
 366                        return -1;
 367                }
 368
 369                if (reset_tree(&c_tree, 0, 1)) {
 370                        strbuf_release(&out);
 371                        return -1;
 372                }
 373
 374                ret = update_index(&out);
 375                strbuf_release(&out);
 376                if (ret)
 377                        return -1;
 378
 379                discard_cache();
 380        }
 381
 382        if (quiet) {
 383                if (refresh_cache(REFRESH_QUIET))
 384                        warning("could not refresh index");
 385        } else {
 386                struct child_process cp = CHILD_PROCESS_INIT;
 387
 388                /*
 389                 * Status is quite simple and could be replaced with calls to
 390                 * wt_status in the future, but it adds complexities which may
 391                 * require more tests.
 392                 */
 393                cp.git_cmd = 1;
 394                cp.dir = prefix;
 395                argv_array_push(&cp.args, "status");
 396                run_command(&cp);
 397        }
 398
 399        return 0;
 400}
 401
 402static int apply_stash(int argc, const char **argv, const char *prefix)
 403{
 404        int ret;
 405        int quiet = 0;
 406        int index = 0;
 407        struct stash_info info;
 408        struct option options[] = {
 409                OPT__QUIET(&quiet, N_("be quiet, only report errors")),
 410                OPT_BOOL(0, "index", &index,
 411                         N_("attempt to recreate the index")),
 412                OPT_END()
 413        };
 414
 415        argc = parse_options(argc, argv, prefix, options,
 416                             git_stash_helper_apply_usage, 0);
 417
 418        if (get_stash_info(&info, argc, argv))
 419                return -1;
 420
 421        ret = do_apply_stash(prefix, &info, index, quiet);
 422        free_stash_info(&info);
 423        return ret;
 424}
 425
 426int cmd_stash__helper(int argc, const char **argv, const char *prefix)
 427{
 428        pid_t pid = getpid();
 429        const char *index_file;
 430
 431        struct option options[] = {
 432                OPT_END()
 433        };
 434
 435        git_config(git_default_config, NULL);
 436
 437        argc = parse_options(argc, argv, prefix, options, git_stash_helper_usage,
 438                             PARSE_OPT_KEEP_UNKNOWN | PARSE_OPT_KEEP_DASHDASH);
 439
 440        index_file = get_index_file();
 441        strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
 442                    (uintmax_t)pid);
 443
 444        if (argc < 1)
 445                usage_with_options(git_stash_helper_usage, options);
 446        if (!strcmp(argv[0], "apply"))
 447                return !!apply_stash(argc, argv, prefix);
 448
 449        usage_msg_opt(xstrfmt(_("unknown subcommand: %s"), argv[0]),
 450                      git_stash_helper_usage, options);
 451}