Skip to content

Commit 183fb44

Browse files
pcloudsgitster
authored andcommitted
restore: add --worktree and --staged
'git checkout <tree-ish> <pathspec>' updates both index and worktree. But updating the index when you want to restore worktree files is non-intuitive. The index contains the data ready for the next commit, and there's no indication that the user will want to commit the restored versions. 'git restore' therefore by default only touches worktree. The user has the option to update either the index with git restore --staged --source=<tree> <path> (1) or update both with git restore --staged --worktree --source=<tree> <path> (2) PS. Orignally I wanted to make worktree update default and form (1) would add index update while also updating the worktree, and the user would need to do "--staged --no-worktree" to update index only. But it looks really confusing that "--staged" option alone updates both. So now form (2) is used for both, which reads much more obvious. PPS. Yes form (1) overlaps with "git reset <rev> <path>". I don't know if we can ever turn "git reset" back to "_always_ reset HEAD and optionally do something else". Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4058199 commit 183fb44

File tree

1 file changed

+68
-6
lines changed

1 file changed

+68
-6
lines changed

builtin/checkout.c

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ struct checkout_opts {
6666
int can_switch_when_in_progress;
6767
int orphan_from_empty_tree;
6868
int empty_pathspec_ok;
69+
int checkout_index;
70+
int checkout_worktree;
6971

7072
const char *new_branch;
7173
const char *new_branch_force;
@@ -397,6 +399,7 @@ static int checkout_paths(const struct checkout_opts *opts,
397399
struct commit *head;
398400
int errs = 0;
399401
struct lock_file lock_file = LOCK_INIT;
402+
int checkout_index;
400403

401404
trace2_cmd_mode(opts->patch_mode ? "patch" : "path");
402405

@@ -422,9 +425,26 @@ static int checkout_paths(const struct checkout_opts *opts,
422425
die(_("Cannot update paths and switch to branch '%s' at the same time."),
423426
opts->new_branch);
424427

425-
if (opts->patch_mode)
426-
return run_add_interactive(revision, "--patch=checkout",
427-
&opts->pathspec);
428+
if (!opts->checkout_worktree && !opts->checkout_index)
429+
die(_("neither '%s' or '%s' is specified"),
430+
"--staged", "--worktree");
431+
432+
if (!opts->checkout_worktree && !opts->from_treeish)
433+
die(_("'%s' must be used when '%s' is not specified"),
434+
"--worktree", "--source");
435+
436+
if (opts->patch_mode) {
437+
const char *patch_mode;
438+
439+
if (opts->checkout_index && opts->checkout_worktree)
440+
patch_mode = "--patch=checkout";
441+
else if (opts->checkout_index && !opts->checkout_worktree)
442+
patch_mode = "--patch=reset";
443+
else
444+
die(_("'%s' with only '%s' is not currently supported"),
445+
"--patch", "--worktree");
446+
return run_add_interactive(revision, patch_mode, &opts->pathspec);
447+
}
428448

429449
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
430450
if (read_cache_preload(&opts->pathspec) < 0)
@@ -482,10 +502,30 @@ static int checkout_paths(const struct checkout_opts *opts,
482502
return 1;
483503

484504
/* Now we are committed to check them out */
485-
errs |= checkout_worktree(opts);
505+
if (opts->checkout_worktree)
506+
errs |= checkout_worktree(opts);
486507

487-
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
488-
die(_("unable to write new index file"));
508+
/*
509+
* Allow updating the index when checking out from the index.
510+
* This is to save new stat info.
511+
*/
512+
if (opts->checkout_worktree && !opts->checkout_index && !opts->source_tree)
513+
checkout_index = 1;
514+
else
515+
checkout_index = opts->checkout_index;
516+
517+
if (checkout_index) {
518+
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
519+
die(_("unable to write new index file"));
520+
} else {
521+
/*
522+
* NEEDSWORK: if --worktree is not specified, we
523+
* should save stat info of checked out files in the
524+
* index to avoid the next (potentially costly)
525+
* refresh. But it's a bit tricker to do...
526+
*/
527+
rollback_lock_file(&lock_file);
528+
}
489529

490530
read_ref_full("HEAD", 0, &rev, NULL);
491531
head = lookup_commit_reference_gently(the_repository, &rev, 1);
@@ -1461,6 +1501,20 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
14611501
if (opts->overlay_mode == 1 && opts->patch_mode)
14621502
die(_("-p and --overlay are mutually exclusive"));
14631503

1504+
if (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {
1505+
if (opts->checkout_index < 0)
1506+
opts->checkout_index = 0;
1507+
if (opts->checkout_worktree < 0)
1508+
opts->checkout_worktree = 0;
1509+
} else {
1510+
if (opts->checkout_index < 0)
1511+
opts->checkout_index = -opts->checkout_index - 1;
1512+
if (opts->checkout_worktree < 0)
1513+
opts->checkout_worktree = -opts->checkout_worktree - 1;
1514+
}
1515+
if (opts->checkout_index < 0 || opts->checkout_worktree < 0)
1516+
BUG("these flags should be non-negative by now");
1517+
14641518
/*
14651519
* From here on, new_branch will contain the branch to be checked out,
14661520
* and new_branch_force and new_orphan_branch will tell us which one of
@@ -1617,6 +1671,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
16171671
opts.orphan_from_empty_tree = 0;
16181672
opts.empty_pathspec_ok = 1;
16191673
opts.overlay_mode = -1;
1674+
opts.checkout_index = -2; /* default on */
1675+
opts.checkout_worktree = -2; /* default on */
16201676

16211677
options = parse_options_dup(checkout_options);
16221678
options = add_common_options(&opts, options);
@@ -1674,6 +1730,10 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
16741730
struct option restore_options[] = {
16751731
OPT_STRING('s', "source", &opts.from_treeish, "<tree-ish>",
16761732
N_("where the checkout from")),
1733+
OPT_BOOL('S', "staged", &opts.checkout_index,
1734+
N_("restore the index")),
1735+
OPT_BOOL('W', "worktree", &opts.checkout_worktree,
1736+
N_("restore the working tree (default)")),
16771737
OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode")),
16781738
OPT_END()
16791739
};
@@ -1684,6 +1744,8 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
16841744
opts.accept_pathspec = 1;
16851745
opts.empty_pathspec_ok = 0;
16861746
opts.overlay_mode = 0;
1747+
opts.checkout_index = -1; /* default off */
1748+
opts.checkout_worktree = -2; /* default on */
16871749

16881750
options = parse_options_dup(restore_options);
16891751
options = add_common_options(&opts, options);

0 commit comments

Comments
 (0)