{"thread":{"id":"49988","subject":"[PATCH 0/8] introduce no-overlay and cached mode in git checkout","startedAt":"2018-12-09T20:05:05Z","lastAt":"2019-02-20T03:52:32Z","messageCount":115,"participants":["Thomas Gummerer","Junio C Hamano","Duy Nguyen","Elijah Newren","Eric Sunshine","Jonathan Nieder","Philip Oakley"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"364871","messageId":"20181209200449.16342-1-t.gummerer@gmail.com","threadId":"49988","inReplyTo":null,"subject":"[PATCH 0/8] introduce no-overlay and cached mode in git checkout","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:41Z","receivedAt":"2018-12-09T20:05:05Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Here's the series I mentioned a couple of times on the list already,\nintroducing a no-overlay mode in 'git checkout'.  The inspiration for\nthis came from Junios message in [*1*].\n\nBasically the idea is to also delete files when the match <pathspec>\nin 'git checkout <tree-ish> -- <pathspec>' in the current tree, but\ndon't match <pathspec> in <tree-ish>.  The rest of the cases are\nalready properly taken care of by 'git checkout'.\n\nThe final step in the series is to actually make use of this in 'git\nstash', which simplifies the code there a bit.  I am however happy to\nhold off on this step until the stash-in-C series is merged, so we\ndon't delay that further.\n\nIn addition to the no-overlay mode, we also add a --cached mode, which\nworks only on the index, thus similar to 'git reset <tree-ish> -- <pathspec>'.\n\nActually deprecating 'git reset <tree-ish> -- <pathspec>' should come\nlater, probably not before Duy's restore-files command lands, as 'git\ncheckout --no-overlay <tree-ish> -- <pathspec>' is a bit cumbersome to\ntype compared to 'git reset <tree-ish> -- <pathspec>'.\n\nMy hope is also that the no-overlay mode could become the new default\nin the restore-files command Duy is currently working on.\n\nNo documentation yet, as I wanted to get this out for review first.\nI'm not familiar with most of the code I touched here, so there may\nwell be much better ways to implement some of this, that I wasn't able\nto figure out.  I'd be very happy with some feedback around that.\n\nAnother thing I'm not sure about is how to deal with conflicts.  In\nthe cached mode this patch series is not dealing with it at all, as\n'git checkout -- <pathspec>' when pathspec matches a file with\nconflicts doesn't update the index.  For the no-overlay mode, the file\nis removed if the corresponding stage is not found in the index.  I'm\nhowever not sure this is the right thing to do in all cases?\n\n*1*: <xmqq4loqplou.fsf@gitster.mtv.corp.google.com>\n\nThomas Gummerer (8):\n  move worktree tests to t24*\n  entry: factor out unlink_entry function\n  entry: support CE_WT_REMOVE flag in checkout_entry\n  read-cache: add invalidate parameter to remove_marked_cache_entries\n  checkout: introduce --{,no-}overlay option\n  checkout: add --cached option\n  checkout: add allow ignoring unmatched pathspec\n  stash: use git checkout --index\n\n builtin/checkout.c                            |  66 +++++++++--\n cache.h                                       |   7 +-\n entry.c                                       |  22 ++++\n git-stash.sh                                  |  12 +-\n read-cache.c                                  |   8 +-\n split-index.c                                 |   2 +-\n t/t2016-checkout-patch.sh                     |   8 ++\n t/t2022-checkout-paths.sh                     |   9 ++\n t/t2025-checkout-no-overlay.sh                |  31 ++++++\n t/t2026-checkout-cached.sh                    | 103 ++++++++++++++++++\n ...-worktree-add.sh => t2400-worktree-add.sh} |   0\n ...ktree-prune.sh => t2401-worktree-prune.sh} |   0\n ...orktree-list.sh => t2402-worktree-list.sh} |   0\n t/t9902-completion.sh                         |   3 +\n unpack-trees.c                                |  21 +---\n 15 files changed, 251 insertions(+), 41 deletions(-)\n create mode 100755 t/t2025-checkout-no-overlay.sh\n create mode 100755 t/t2026-checkout-cached.sh\n rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n\n-- \n2.20.0.rc2.411.g8f28e744c2\n\n"},{"id":"364872","messageId":"20181209200449.16342-2-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH 1/8] move worktree tests to t24*","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:42Z","receivedAt":"2018-12-09T20:05:05Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"The 'git worktree' command used to be just another mode in 'git\ncheckout', namely 'git checkout --to'.  When the tests for the latter\nwere retrofitted for the former, the test name was adjusted, but the\ntest number was kept, even though the test is testing a different\ncommand now.  t/README states: \"Second digit tells the particular\ncommand we are testing.\", so 'git worktree' should have a separate\nnumber just for itself.\n\nMove the worktree tests to t24* to adhere to that guideline. We're\ngoing to make use of the free'd up numbers in a subsequent commit.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n t/{t2025-worktree-add.sh => t2400-worktree-add.sh}     | 0\n t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} | 0\n t/{t2027-worktree-list.sh => t2402-worktree-list.sh}   | 0\n 3 files changed, 0 insertions(+), 0 deletions(-)\n rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n\ndiff --git a/t/t2025-worktree-add.sh b/t/t2400-worktree-add.sh\nsimilarity index 100%\nrename from t/t2025-worktree-add.sh\nrename to t/t2400-worktree-add.sh\ndiff --git a/t/t2026-worktree-prune.sh b/t/t2401-worktree-prune.sh\nsimilarity index 100%\nrename from t/t2026-worktree-prune.sh\nrename to t/t2401-worktree-prune.sh\ndiff --git a/t/t2027-worktree-list.sh b/t/t2402-worktree-list.sh\nsimilarity index 100%\nrename from t/t2027-worktree-list.sh\nrename to t/t2402-worktree-list.sh\n-- \n2.20.0.405.gbc1bbc6f85\n\n"},{"id":"364873","messageId":"20181209200449.16342-4-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:44Z","receivedAt":"2018-12-09T20:05:05Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"'checkout_entry()' currently only supports creating new entries in the\nworking tree, but not deleting them.  Add the ability to remove\nentries at the same time if the entry is marked with the CE_WT_REMOVE\nflag.\n\nCurrently this doesn't have any effect, as the CE_WT_REMOVE flag is\nonly used in unpack-tree, however we will make use of this in a\nsubsequent step in the series.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n entry.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/entry.c b/entry.c\nindex 3ec148ceee..cd1c6601b6 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -441,6 +441,13 @@ int checkout_entry(struct cache_entry *ce,\n \tstatic struct strbuf path = STRBUF_INIT;\n \tstruct stat st;\n \n+\tif (ce->ce_flags & CE_WT_REMOVE) {\n+\t\tif (topath)\n+\t\t\tBUG(\"Can't remove entry to a path\");\n+\t\tunlink_entry(ce);\n+\t\treturn 0;\n+\t}\n+\n \tif (topath)\n \t\treturn write_entry(ce, topath, state, 1);\n \n-- \n2.20.0.405.gbc1bbc6f85\n\n"},{"id":"364874","messageId":"20181209200449.16342-3-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH 2/8] entry: factor out unlink_entry function","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:43Z","receivedAt":"2018-12-09T20:05:05Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Factor out the 'unlink_entry()' function from unpack-trees.c to\nentry.c.  It will be used in other places as well in subsequent\nsteps.\n\nAs it's no longer a static function, also move the documentation to\nthe header file to make it more discoverable.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n cache.h        |  5 +++++\n entry.c        | 15 +++++++++++++++\n unpack-trees.c | 19 -------------------\n 3 files changed, 20 insertions(+), 19 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ca36b44ee0..c1c953e810 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1542,6 +1542,11 @@ struct checkout {\n extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);\n extern void enable_delayed_checkout(struct checkout *state);\n extern int finish_delayed_checkout(struct checkout *state);\n+/*\n+ * Unlink the last component and schedule the leading directories for\n+ * removal, such that empty directories get removed.\n+ */\n+extern void unlink_entry(const struct cache_entry *ce);\n \n struct cache_def {\n \tstruct strbuf path;\ndiff --git a/entry.c b/entry.c\nindex 5d136c5d55..3ec148ceee 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -508,3 +508,18 @@ int checkout_entry(struct cache_entry *ce,\n \tcreate_directories(path.buf, path.len, state);\n \treturn write_entry(ce, path.buf, state, 0);\n }\n+\n+void unlink_entry(const struct cache_entry *ce)\n+{\n+\tconst struct submodule *sub = submodule_from_ce(ce);\n+\tif (sub) {\n+\t\t/* state.force is set at the caller. */\n+\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n+\t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n+\t}\n+\tif (!check_leading_path(ce->name, ce_namelen(ce)))\n+\t\treturn;\n+\tif (remove_or_warn(ce->ce_mode, ce->name))\n+\t\treturn;\n+\tschedule_dir_for_removal(ce->name, ce_namelen(ce));\n+}\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 7570df481b..e8d1a6ac50 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -300,25 +300,6 @@ static void load_gitmodules_file(struct index_state *index,\n \t}\n }\n \n-/*\n- * Unlink the last component and schedule the leading directories for\n- * removal, such that empty directories get removed.\n- */\n-static void unlink_entry(const struct cache_entry *ce)\n-{\n-\tconst struct submodule *sub = submodule_from_ce(ce);\n-\tif (sub) {\n-\t\t/* state.force is set at the caller. */\n-\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n-\t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n-\t}\n-\tif (!check_leading_path(ce->name, ce_namelen(ce)))\n-\t\treturn;\n-\tif (remove_or_warn(ce->ce_mode, ce->name))\n-\t\treturn;\n-\tschedule_dir_for_removal(ce->name, ce_namelen(ce));\n-}\n-\n static struct progress *get_progress(struct unpack_trees_options *o)\n {\n \tunsigned cnt = 0, total = 0;\n-- \n2.20.0.405.gbc1bbc6f85\n\n"},{"id":"364875","messageId":"20181209200449.16342-5-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:45Z","receivedAt":"2018-12-09T20:05:09Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"When marking cache entries for removal, and later removing them all at\nonce using 'remove_marked_cache_entries()', cache entries currently\nhave to be invalidated manually in the cache tree and in the untracked\ncache.\n\nAdd an invalidate flag to the function.  With the flag set, the\nfunction will take care of invalidating the path in the cache tree and\nin the untracked cache.\n\nThis will be useful in a subsequent commit.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n\nFor the two current callsites, unpack-trees seems to do this\ninvalidation itself internally.  I don't quite understand why we don't\nneed it in split-index mode though.  I assume it's because the cache\ntree in the main index would already have been invalidated?  I didn't\nhave much time to dig, but couldn't produce any failures with it\neither, so I assume not invalidating paths is the right thing to do\nhere.\n\n cache.h        | 2 +-\n read-cache.c   | 8 +++++++-\n split-index.c  | 2 +-\n unpack-trees.c | 2 +-\n 4 files changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c1c953e810..1deee48f5b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -751,7 +751,7 @@ extern void rename_index_entry_at(struct index_state *, int pos, const char *new\n /* Remove entry, return true if there are more entries to go. */\n extern int remove_index_entry_at(struct index_state *, int pos);\n \n-extern void remove_marked_cache_entries(struct index_state *istate);\n+extern void remove_marked_cache_entries(struct index_state *istate, int invalidate);\n extern int remove_file_from_index(struct index_state *, const char *path);\n #define ADD_CACHE_VERBOSE 1\n #define ADD_CACHE_PRETEND 2\ndiff --git a/read-cache.c b/read-cache.c\nindex 4ca81286c0..d86a06acba 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -590,13 +590,19 @@ int remove_index_entry_at(struct index_state *istate, int pos)\n  * CE_REMOVE is set in ce_flags.  This is much more effective than\n  * calling remove_index_entry_at() for each entry to be removed.\n  */\n-void remove_marked_cache_entries(struct index_state *istate)\n+void remove_marked_cache_entries(struct index_state *istate, int invalidate)\n {\n \tstruct cache_entry **ce_array = istate->cache;\n \tunsigned int i, j;\n \n \tfor (i = j = 0; i < istate->cache_nr; i++) {\n \t\tif (ce_array[i]->ce_flags & CE_REMOVE) {\n+\t\t\tif (invalidate) {\n+\t\t\t\tcache_tree_invalidate_path(istate,\n+\t\t\t\t\t\t\t   ce_array[i]->name);\n+\t\t\t\tuntracked_cache_remove_from_index(istate,\n+\t\t\t\t\t\t\t\t  ce_array[i]->name);\n+\t\t\t}\n \t\t\tremove_name_hash(istate, ce_array[i]);\n \t\t\tsave_or_free_index_entry(istate, ce_array[i]);\n \t\t}\ndiff --git a/split-index.c b/split-index.c\nindex 5820412dc5..8aebc3661b 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -162,7 +162,7 @@ void merge_base_index(struct index_state *istate)\n \tewah_each_bit(si->replace_bitmap, replace_entry, istate);\n \tewah_each_bit(si->delete_bitmap, mark_entry_for_delete, istate);\n \tif (si->nr_deletions)\n-\t\tremove_marked_cache_entries(istate);\n+\t\tremove_marked_cache_entries(istate, 0);\n \n \tfor (i = si->nr_replacements; i < si->saved_cache_nr; i++) {\n \t\tif (!ce_namelen(si->saved_cache[i]))\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex e8d1a6ac50..8e6afa924d 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -392,7 +392,7 @@ static int check_updates(struct unpack_trees_options *o)\n \t\t\t\tunlink_entry(ce);\n \t\t}\n \t}\n-\tremove_marked_cache_entries(index);\n+\tremove_marked_cache_entries(index, 0);\n \tremove_scheduled_dirs();\n \n \tif (should_update_submodules() && o->update && !o->dry_run)\n-- \n2.20.0.405.gbc1bbc6f85\n\n"},{"id":"364876","messageId":"20181209200449.16342-6-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH 5/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:46Z","receivedAt":"2018-12-09T20:05:09Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git checkout' is defined as an overlay operation, which\nmeans that if in 'git checkout <tree-ish> -- [<pathspec>]' we have an\nentry in the index that matches <pathspec>, but that doesn't exist in\n<tree-ish>, that entry will not be removed from the index or the\nworking tree.\n\nIntroduce a new --{,no-}overlay option, which allows using 'git\ncheckout' in non-overlay mode, thus removing files from the working\ntree if they do not exist in <tree-ish> but match <pathspec>.\n\nNote that 'git checkout -p <tree-ish> -- [<pathspec>]' already works\nthis way, so no changes are needed for the patch mode.  We disallow\n'git checkout --overlay -p' to avoid confusing users who would expect\nto be able to force overlay mode in 'git checkout -p' this way.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n builtin/checkout.c             | 64 +++++++++++++++++++++++++++-------\n t/t2025-checkout-no-overlay.sh | 47 +++++++++++++++++++++++++\n t/t9902-completion.sh          |  1 +\n 3 files changed, 99 insertions(+), 13 deletions(-)\n create mode 100755 t/t2025-checkout-no-overlay.sh\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex acdafc6e4c..0aef35bbc4 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -44,6 +44,7 @@ struct checkout_opts {\n \tint ignore_skipworktree;\n \tint ignore_other_worktrees;\n \tint show_progress;\n+\tint overlay_mode;\n \t/*\n \t * If new checkout options are added, skip_merge_working_tree\n \t * should be updated accordingly.\n@@ -132,7 +133,8 @@ static int skip_same_name(const struct cache_entry *ce, int pos)\n \treturn pos;\n }\n \n-static int check_stage(int stage, const struct cache_entry *ce, int pos)\n+static int check_stage(int stage, const struct cache_entry *ce, int pos,\n+\t\t       int overlay_mode)\n {\n \twhile (pos < active_nr &&\n \t       !strcmp(active_cache[pos]->name, ce->name)) {\n@@ -140,6 +142,8 @@ static int check_stage(int stage, const struct cache_entry *ce, int pos)\n \t\t\treturn 0;\n \t\tpos++;\n \t}\n+\tif (!overlay_mode)\n+\t\treturn 0;\n \tif (stage == 2)\n \t\treturn error(_(\"path '%s' does not have our version\"), ce->name);\n \telse\n@@ -165,7 +169,7 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)\n }\n \n static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n-\t\t\t  const struct checkout *state)\n+\t\t\t  const struct checkout *state, int overlay_mode)\n {\n \twhile (pos < active_nr &&\n \t       !strcmp(active_cache[pos]->name, ce->name)) {\n@@ -173,6 +177,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n \t\t\treturn checkout_entry(active_cache[pos], state, NULL);\n \t\tpos++;\n \t}\n+\tif (!overlay_mode) {\n+\t\tunlink_entry(ce);\n+\t\treturn 0;\n+\t}\n \tif (stage == 2)\n \t\treturn error(_(\"path '%s' does not have our version\"), ce->name);\n \telse\n@@ -302,15 +310,29 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\tce->ce_flags &= ~CE_MATCHED;\n \t\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n \t\t\tcontinue;\n-\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n-\t\t\t/*\n-\t\t\t * \"git checkout tree-ish -- path\", but this entry\n-\t\t\t * is in the original index; it will not be checked\n-\t\t\t * out to the working tree and it does not matter\n-\t\t\t * if pathspec matched this entry.  We will not do\n-\t\t\t * anything to this entry at all.\n-\t\t\t */\n-\t\t\tcontinue;\n+\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) {\n+\t\t\tif (!opts->overlay_mode &&\n+\t\t\t    ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {\n+\t\t\t\t/*\n+\t\t\t\t * \"git checkout --no-overlay <tree-ish> -- path\",\n+\t\t\t\t * and the path is not in tree-ish, but is in\n+\t\t\t\t * the current index, which means that it should \n+\t\t\t\t * be removed.\n+\t\t\t\t */\n+\t\t\t\tce->ce_flags |= CE_MATCHED | CE_REMOVE | CE_WT_REMOVE;\n+\t\t\t\tcontinue;\n+\t\t\t} else {\n+\t\t\t\t/*\n+\t\t\t\t * \"git checkout tree-ish -- path\", but this\n+\t\t\t\t * entry is in the original index; it will not\n+\t\t\t\t * be checked out to the working tree and it\n+\t\t\t\t * does not matter if pathspec matched this\n+\t\t\t\t * entry.  We will not do anything to this entry\n+\t\t\t\t * at all.\n+\t\t\t\t */\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n \t\t/*\n \t\t * Either this entry came from the tree-ish we are\n \t\t * checking the paths out of, or we are checking out\n@@ -348,7 +370,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\tif (opts->force) {\n \t\t\t\twarning(_(\"path '%s' is unmerged\"), ce->name);\n \t\t\t} else if (opts->writeout_stage) {\n-\t\t\t\terrs |= check_stage(opts->writeout_stage, ce, pos);\n+\t\t\t\terrs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode);\n \t\t\t} else if (opts->merge) {\n \t\t\t\terrs |= check_stages((1<<2) | (1<<3), ce, pos);\n \t\t\t} else {\n@@ -375,12 +397,14 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (opts->writeout_stage)\n-\t\t\t\terrs |= checkout_stage(opts->writeout_stage, ce, pos, &state);\n+\t\t\t\terrs |= checkout_stage(opts->writeout_stage, ce, pos, &state, opts->overlay_mode);\n \t\t\telse if (opts->merge)\n \t\t\t\terrs |= checkout_merged(pos, &state);\n \t\t\tpos = skip_same_name(ce, pos) - 1;\n \t\t}\n \t}\n+\tremove_marked_cache_entries(&the_index, 1);\n+\tremove_scheduled_dirs();\n \terrs |= finish_delayed_checkout(&state);\n \n \tif (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))\n@@ -542,6 +566,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,\n \t * opts->show_progress only impacts output so doesn't require a merge\n \t */\n \n+\t/*\n+\t * opts->overlay_mode cannot be used with switching branches so is\n+\t * not tested here\n+\t */\n+\n \t/*\n \t * If we aren't creating a new branch any changes or updates will\n \t * happen in the existing branch.  Since that could only be updating\n@@ -1178,6 +1207,10 @@ static int checkout_branch(struct checkout_opts *opts,\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n \t\t    \"--patch\");\n \n+\tif (!opts->overlay_mode)\n+\t\tdie(_(\"'%s' cannot be used with switching branches\"),\n+\t\t    \"--no-overlay\");\n+\n \tif (opts->writeout_stage)\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n \t\t    \"--ours/--theirs\");\n@@ -1266,6 +1299,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n \t\tOPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1274,6 +1308,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \topts.overwrite_ignore = 1;\n \topts.prefix = prefix;\n \topts.show_progress = -1;\n+\topts.overlay_mode = -1;\n \n \tgit_config(git_checkout_config, &opts);\n \n@@ -1297,6 +1332,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tif ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)\n \t\tdie(_(\"-b, -B and --orphan are mutually exclusive\"));\n \n+\tif (opts.overlay_mode == 1 && opts.patch_mode)\n+\t\tdie(_(\"-p and --overlay are mutually exclusive\"));\n+\n \t/*\n \t * From here on, new_branch will contain the branch to be checked out,\n \t * and new_branch_force and new_orphan_branch will tell us which one of\ndiff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh\nnew file mode 100755\nindex 0000000000..3575321382\n--- /dev/null\n+++ b/t/t2025-checkout-no-overlay.sh\n@@ -0,0 +1,47 @@\n+#!/bin/sh\n+\n+test_description='checkout --no-overlay <tree-ish> -- <pathspec>'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\tgit commit --allow-empty -m \"initial\"\n+'\n+\n+test_expect_success 'checkout --no-overlay deletes files not in <tree>' '\n+\t>file &&\n+\tmkdir dir &&\n+\t>dir/file1 &&\n+\tgit add file dir/file1 &&\n+\tgit checkout --no-overlay HEAD -- file &&\n+\ttest_path_is_missing file &&\n+\ttest_path_is_file dir/file1\n+'\n+\n+test_expect_success 'checkout --no-overlay removing last file from directory' '\n+\tgit checkout --no-overlay HEAD -- dir/file1 &&\n+\ttest_path_is_missing dir\n+'\n+\n+test_expect_success 'checkout -p --overlay is disallowed' '\n+\ttest_must_fail git checkout -p --overlay HEAD 2>actual &&\n+\ttest_i18ngrep \"fatal: -p and --overlay are mutually exclusive\" actual\n+'\n+\n+test_expect_success '--no-overlay --theirs with M/D conflict deletes file' '\n+\ttest_commit file1 file1 &&\n+\ttest_commit file2 file2 &&\n+\tgit rm --cached file1 &&\n+\techo 1234 >file1 &&\n+\tF1=$(git rev-parse HEAD:file1) &&\n+\tF2=$(git rev-parse HEAD:file2) &&\n+\t{\n+\t\techo \"100644 $F1 1\tfile1\" &&\n+\t\techo \"100644 $F2 2\tfile1\"\n+\t} | git update-index --index-info &&\n+\ttest_path_is_file file1 &&\n+\tgit checkout --theirs --no-overlay -- file1 &&\n+\ttest_path_is_missing file1\n+'\n+\n+test_done\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex 175f83d704..a3fd9a9630 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1436,6 +1436,7 @@ test_expect_success 'double dash \"git checkout\"' '\n \t--progress Z\n \t--no-quiet Z\n \t--no-... Z\n+\t--overlay Z\n \tEOF\n '\n \n-- \n2.20.0.405.gbc1bbc6f85\n\n"},{"id":"364877","messageId":"20181209200449.16342-7-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH 6/8] checkout: add --cached option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:47Z","receivedAt":"2018-12-09T20:05:12Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Add a new --cached option to git checkout, which works only on the\nindex, but not the working tree, similar to what 'git reset <tree-ish>\n-- <pathspec>... does.  Indeed the tests are adapted from the 'git\nreset' tests.\n\nIn the longer term the idea is to potentially deprecate 'git reset\n<tree-ish> -- <pathspec>...', so the 'git reset' command becomes only\nabout re-pointing the HEAD, and not also about copying entries from\n<tree-ish> to the index.\n\nNote that 'git checkout' by default works in overlay mode, meaning\nfiles that match the pathspec that don't exist in <tree-ish>, but\nexist in the index would not be removed.  'git checkout --no-overlay\n--cached' can be used to get the same behaviour as 'git reset\n<tree-ish> -- <pathspec>'.\n\nOne thing this patch doesn't currently deal with is conflicts.\nCurrently 'git checkout --{ours,theirs} -- <file-with-conflicts>'\ndoesn't do anything with the index, so the --cached option just\nmirrors that behaviour.  But given it doesn't even deal with\nconflicts, the '--cached' option doesn't make much sense when no\n<tree-ish> is given.  As it operates only on the index, it's always a\nno-op if no tree-ish is given.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n\nMaybe we can just disallow --cached without <tree-ish> given for now,\nand possibly later allow it with some different behaviour for\nconflicts, not sure what the best way forward here is.  We can also\njust make it update the index as appropriate, and have it behave\ndifferent than 'git checkout' curerntly does when handling conflicts?\n\n builtin/checkout.c         |  26 ++++++++--\n t/t2016-checkout-patch.sh  |   8 +++\n t/t2026-checkout-cached.sh | 103 +++++++++++++++++++++++++++++++++++++\n t/t9902-completion.sh      |   1 +\n 4 files changed, 135 insertions(+), 3 deletions(-)\n create mode 100755 t/t2026-checkout-cached.sh\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 0aef35bbc4..6ba85e9de5 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -45,6 +45,7 @@ struct checkout_opts {\n \tint ignore_other_worktrees;\n \tint show_progress;\n \tint overlay_mode;\n+\tint cached;\n \t/*\n \t * If new checkout options are added, skip_merge_working_tree\n \t * should be updated accordingly.\n@@ -288,6 +289,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\tdie(_(\"Cannot update paths and switch to branch '%s' at the same time.\"),\n \t\t    opts->new_branch);\n \n+\tif (opts->patch_mode && opts->cached)\n+\t\treturn run_add_interactive(revision, \"--patch=reset\",\n+\t\t\t\t\t   &opts->pathspec);\n+\n \tif (opts->patch_mode)\n \t\treturn run_add_interactive(revision, \"--patch=checkout\",\n \t\t\t\t\t   &opts->pathspec);\n@@ -319,7 +324,9 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t\t * the current index, which means that it should \n \t\t\t\t * be removed.\n \t\t\t\t */\n-\t\t\t\tce->ce_flags |= CE_MATCHED | CE_REMOVE | CE_WT_REMOVE;\n+\t\t\t\tce->ce_flags |= CE_MATCHED | CE_REMOVE;\n+\t\t\t\tif (!opts->cached)\n+\t\t\t\t\tce->ce_flags |= CE_WT_REMOVE;\n \t\t\t\tcontinue;\n \t\t\t} else {\n \t\t\t\t/*\n@@ -392,6 +399,9 @@ static int checkout_paths(const struct checkout_opts *opts,\n \tfor (pos = 0; pos < active_nr; pos++) {\n \t\tstruct cache_entry *ce = active_cache[pos];\n \t\tif (ce->ce_flags & CE_MATCHED) {\n+\t\t\tif (opts->cached) {\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!ce_stage(ce)) {\n \t\t\t\terrs |= checkout_entry(ce, &state, NULL);\n \t\t\t\tcontinue;\n@@ -571,6 +581,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,\n \t * not tested here\n \t */\n \n+\t/*\n+\t * opts->cached cannot be used with switching branches so is\n+\t * not tested here\n+\t */\n+\n \t/*\n \t * If we aren't creating a new branch any changes or updates will\n \t * happen in the existing branch.  Since that could only be updating\n@@ -1207,9 +1222,13 @@ static int checkout_branch(struct checkout_opts *opts,\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n \t\t    \"--patch\");\n \n-\tif (!opts->overlay_mode)\n+\tif (opts->overlay_mode != -1)\n+\t\tdie(_(\"'%s' cannot be used with switching branches\"),\n+\t\t    \"--overlay/--no-overlay\");\n+\n+\tif (opts->cached)\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n-\t\t    \"--no-overlay\");\n+\t\t    \"--cached\");\n \n \tif (opts->writeout_stage)\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n@@ -1300,6 +1319,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n \t\tOPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n \t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n+\t\tOPT_BOOL(0, \"cached\", &opts.cached, N_(\"work on the index only\")),\n \t\tOPT_END(),\n \t};\n \ndiff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh\nindex 47aeb0b167..e8774046e0 100755\n--- a/t/t2016-checkout-patch.sh\n+++ b/t/t2016-checkout-patch.sh\n@@ -108,6 +108,14 @@ test_expect_success PERL 'path limiting works: foo inside dir' '\n \tverify_state dir/foo head head\n '\n \n+test_expect_success PERL 'git checkout --cached -p' '\n+\tset_and_save_state dir/foo work work &&\n+\ttest_write_lines n y | git checkout --cached -p >output &&\n+\tverify_state dir/foo work head &&\n+\tverify_saved_state bar &&\n+\ttest_i18ngrep \"Unstage\" output\n+'\n+\n test_expect_success PERL 'none of this moved HEAD' '\n \tverify_saved_head\n '\ndiff --git a/t/t2026-checkout-cached.sh b/t/t2026-checkout-cached.sh\nnew file mode 100755\nindex 0000000000..1b66192727\n--- /dev/null\n+++ b/t/t2026-checkout-cached.sh\n@@ -0,0 +1,103 @@\n+#!/bin/sh\n+\n+test_description='checkout --cached <pathspec>'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'checkout --cached <pathspec>' '\n+\techo 1 >file1 &&\n+\techo 2 >file2 &&\n+\tgit add file1 file2 &&\n+\ttest_tick &&\n+\tgit commit -m files &&\n+\tgit rm file2 &&\n+\techo 3 >file3 &&\n+\techo 4 >file1 &&\n+\tgit add file1 file3 &&\n+\tgit checkout --cached HEAD -- file1 file2 &&\n+\ttest_must_fail git diff --quiet &&\n+\n+\tcat >expect <<-\\EOF &&\n+\tdiff --git a/file1 b/file1\n+\tindex d00491f..b8626c4 100644\n+\t--- a/file1\n+\t+++ b/file1\n+\t@@ -1 +1 @@\n+\t-1\n+\t+4\n+\tdiff --git a/file2 b/file2\n+\tdeleted file mode 100644\n+\tindex 0cfbf08..0000000\n+\t--- a/file2\n+\t+++ /dev/null\n+\t@@ -1 +0,0 @@\n+\t-2\n+\tEOF\n+\tgit diff >actual &&\n+\ttest_cmp expect actual &&\n+\n+\tcat >expect <<-\\EOF &&\n+\tdiff --git a/file3 b/file3\n+\tnew file mode 100644\n+\tindex 0000000..00750ed\n+\t--- /dev/null\n+\t+++ b/file3\n+\t@@ -0,0 +1 @@\n+\t+3\n+\tEOF\n+\tgit diff --cached >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success 'checking out an unmodified path is a no-op' '\n+\tgit reset --hard &&\n+\tgit checkout --cached HEAD -- file1 &&\n+\tgit diff-files --exit-code &&\n+\tgit diff-index --cached --exit-code HEAD\n+'\n+\n+test_expect_success 'checking out specific path that is unmerged' '\n+\ttest_commit file3 file3 &&\n+\tgit rm --cached file2 &&\n+\techo 1234 >file2 &&\n+\tF1=$(git rev-parse HEAD:file1) &&\n+\tF2=$(git rev-parse HEAD:file2) &&\n+\tF3=$(git rev-parse HEAD:file3) &&\n+\t{\n+\t\techo \"100644 $F1 1\tfile2\" &&\n+\t\techo \"100644 $F2 2\tfile2\" &&\n+\t\techo \"100644 $F3 3\tfile2\"\n+\t} | git update-index --index-info &&\n+\tgit ls-files -u &&\n+\tgit checkout --cached HEAD file2 &&\n+\ttest_must_fail git diff --quiet &&\n+\tgit diff-index --exit-code --cached HEAD\n+'\n+\n+test_expect_success '--cached without --no-overlay does not remove entry from index' '\n+\ttest_must_fail git checkout --cached HEAD^ file3 &&\n+\tgit ls-files --error-unmatch -- file3\n+'\n+\n+test_expect_success 'file is removed from the index with --no-overlay' '\n+\tgit checkout --cached --no-overlay HEAD^ file3 &&\n+\ttest_path_is_file file3 &&\n+\ttest_must_fail git ls-files --error-unmatch -- file3\n+'\n+\n+test_expect_success 'test checkout --cached --no-overlay at given paths' '\n+\tmkdir sub &&\n+\t>sub/file1 &&\n+\t>sub/file2 &&\n+\tgit update-index --add sub/file1 sub/file2 &&\n+\tT=$(git write-tree) &&\n+\tgit checkout --cached --no-overlay HEAD sub/file2 &&\n+\ttest_must_fail git diff --quiet &&\n+\tU=$(git write-tree) &&\n+\techo \"$T\" &&\n+\techo \"$U\" &&\n+\ttest_must_fail git diff-index --cached --exit-code \"$T\" &&\n+\ttest \"$T\" != \"$U\"\n+'\n+\n+test_done\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex a3fd9a9630..cbc304ace8 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1437,6 +1437,7 @@ test_expect_success 'double dash \"git checkout\"' '\n \t--no-quiet Z\n \t--no-... Z\n \t--overlay Z\n+\t--cached Z\n \tEOF\n '\n \n-- \n2.20.0.405.gbc1bbc6f85\n\n"},{"id":"364878","messageId":"20181209200449.16342-8-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH 7/8] checkout: allow ignoring unmatched pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:48Z","receivedAt":"2018-12-09T20:05:12Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently when 'git checkout -- <pathspec>...' is invoked with\nmultiple pathspecs, where one or more of the pathspecs don't match\nanything, checkout errors out.\n\nThis can be inconvenient in some cases, such as when using git\ncheckout from a script.  Introduce a new --ignore-unmatched option,\nwhich which allows us to ignore a non-matching pathspec instead of\nerroring out.\n\nIn a subsequent commit we're going to start using 'git checkout' in\n'git stash' and are going to make use of this feature.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n builtin/checkout.c        | 10 +++++++++-\n t/t2022-checkout-paths.sh |  9 +++++++++\n t/t9902-completion.sh     |  1 +\n 3 files changed, 19 insertions(+), 1 deletion(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 6ba85e9de5..7e7b5cd1d3 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -46,6 +46,7 @@ struct checkout_opts {\n \tint show_progress;\n \tint overlay_mode;\n \tint cached;\n+\tint ignore_unmatched;\n \t/*\n \t * If new checkout options are added, skip_merge_working_tree\n \t * should be updated accordingly.\n@@ -358,7 +359,8 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\tce->ce_flags |= CE_MATCHED;\n \t}\n \n-\tif (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {\n+\tif (!opts->ignore_unmatched &&\n+\t    report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {\n \t\tfree(ps_matched);\n \t\treturn 1;\n \t}\n@@ -586,6 +588,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,\n \t * not tested here\n \t */\n \n+\t/*\n+\t * opts->ignore_unmatched cannot be used with switching branches so is\n+\t * not tested here\n+\t */\n+\n \t/*\n \t * If we aren't creating a new branch any changes or updates will\n \t * happen in the existing branch.  Since that could only be updating\n@@ -1320,6 +1327,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n \t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n \t\tOPT_BOOL(0, \"cached\", &opts.cached, N_(\"work on the index only\")),\n+\t\tOPT_BOOL(0, \"ignore-unmatched\", &opts.ignore_unmatched, N_(\"don't error on unmatched pathspecs\")),\n \t\tOPT_END(),\n \t};\n \ndiff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh\nindex fc3eb43b89..b44cdf7b63 100755\n--- a/t/t2022-checkout-paths.sh\n+++ b/t/t2022-checkout-paths.sh\n@@ -78,4 +78,13 @@ test_expect_success 'do not touch files that are already up-to-date' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'checkout --ignore-unmatched' '\n+\ttest_commit file1 &&\n+\techo changed >file1.t &&\n+\tgit checkout --ignore-unmatched -- file1.t unknown-file &&\n+\techo file1 >expect &&\n+\ttest_cmp expect file1.t\n+\n+'\n+\n test_done\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex cbc304ace8..475debcf95 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1438,6 +1438,7 @@ test_expect_success 'double dash \"git checkout\"' '\n \t--no-... Z\n \t--overlay Z\n \t--cached Z\n+\t--ignore-unmatched Z\n \tEOF\n '\n \n-- \n2.20.0.405.gbc1bbc6f85\n\n"},{"id":"364879","messageId":"20181209200449.16342-9-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH 8/8] stash: use git checkout --no-overlay","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-09T20:04:49Z","receivedAt":"2018-12-09T20:05:14Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Now that we have 'git checkout --no-overlay', we can use it in git\nstash, making the codepaths for 'git stash push' with and without\npathspec more similar, and thus easier to follow.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n\nAs mentioned in the cover letter, not sure if we want to apply this\nnow.  There are two reasons I did this:\n- Showing the new functionality of git checkout\n- Increased test coverage, as we are running the new code with all git\n  stash tests for free, which helped look at some cases that I was\n  missing initially.\n\n git-stash.sh | 12 ++++--------\n 1 file changed, 4 insertions(+), 8 deletions(-)\n\ndiff --git a/git-stash.sh b/git-stash.sh\nindex 94793c1a91..67be04d996 100755\n--- a/git-stash.sh\n+++ b/git-stash.sh\n@@ -314,19 +314,15 @@ push_stash () {\n \n \tif test -z \"$patch_mode\"\n \tthen\n-\t\ttest \"$untracked\" = \"all\" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=\n-\t\tif test -n \"$untracked\" && test $# = 0\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\t\tgit clean --force --quiet -d $CLEAN_X_OPTION -- \"$@\"\n \t\tfi\n \n \t\tif test $# != 0\n \t\tthen\n-\t\t\ttest -z \"$untracked\" && UPDATE_OPTION=\"-u\" || UPDATE_OPTION=\n-\t\t\ttest \"$untracked\" = \"all\" && FORCE_OPTION=\"--force\" || FORCE_OPTION=\n-\t\t\tgit add $UPDATE_OPTION $FORCE_OPTION -- \"$@\"\n-\t\t\tgit diff-index -p --cached --binary HEAD -- \"$@\" |\n-\t\t\tgit apply --index -R\n+\t\t\tgit checkout --quiet --no-overlay --ignore-unmatched HEAD -- \"$@\"\n \t\telse\n \t\t\tgit reset --hard -q\n \t\tfi\n-- \n2.20.0.405.gbc1bbc6f85\n\n"},{"id":"364898","messageId":"xmqqa7le2gc2.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"Re: [PATCH 0/8] introduce no-overlay and cached mode in git checkout","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-10T03:47:25Z","receivedAt":"2018-12-10T03:47:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> Basically the idea is to also delete files when the match <pathspec>\n> in 'git checkout <tree-ish> -- <pathspec>' in the current tree, but\n> don't match <pathspec> in <tree-ish>.\n\nI cannot quite parse it, but perhaps.\n\n\t\"git checkout --no-overlay <tree-ish> -- <pathspec>\" can\n\tremove paths in the index and in the working tree that match\n\t<pathspec>, if they do not appear in <tree-ish>.\n\nIf a new file D/F is in the index and in the working tree but not in\nHEAD, \"git checkout HEAD D/\" or \"git checkout HEAD D/F\" would not\nremove D/F from the index or the working tree.\n\nWith the --no-overlay option, it would, and that is often closer to\nthe wish of the user who wanted to say \"restore the working tree\nstate of D/ (or D/F) from the state recorded in HEAD\".\n\n> The final step in the series is to actually make use of this in 'git\n> stash', which simplifies the code there a bit.  I am however happy to\n> hold off on this step until the stash-in-C series is merged, so we\n> don't delay that further.\n\nI think that is probably a good idea, for now.\n\n> In addition to the no-overlay mode, we also add a --cached mode, which\n> works only on the index, thus similar to 'git reset <tree-ish> -- <pathspec>'.\n>\n> Actually deprecating 'git reset <tree-ish> -- <pathspec>' should come\n> later,...\n\nOr we may not even need to deprecate it.  IIRC, what \"stash\" wished\nto exist was \"git reset --hard <tree-ish> -- <pathspec>\", which, if\nthe command followed \"--cached/--index\" convention, would have been\ncalled \"git reset --index ...\".  Did we actually have the need for\n\"--cached\" mode?\n\n> probably not before Duy's restore-files command lands, as 'git\n> checkout --no-overlay <tree-ish> -- <pathspec>' is a bit cumbersome to\n> type compared to 'git reset <tree-ish> -- <pathspec>'.\n\nYes, between \"checkout --cached\" and \"checkout --no-overlay\", the\nlatter is much more important, as the latter is what a missing \"git\nreset --hard <tree-ish> -- <pathspec>\" would have been, but the\nformer can be written with an existing command.\n\n> My hope is also that the no-overlay mode could become the new default\n> in the restore-files command Duy is currently working on.\n\nYup, that is my hope, too ;-).\n"},{"id":"364899","messageId":"xmqq5zw22g9n.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"20181209200449.16342-2-t.gummerer@gmail.com","subject":"Re: [PATCH 1/8] move worktree tests to t24*","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-10T03:48:52Z","receivedAt":"2018-12-10T03:48:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> The 'git worktree' command used to be just another mode in 'git\n> checkout', namely 'git checkout --to'.  When the tests for the latter\n> were retrofitted for the former, the test name was adjusted, but the\n> test number was kept, even though the test is testing a different\n> command now.  t/README states: \"Second digit tells the particular\n> command we are testing.\", so 'git worktree' should have a separate\n> number just for itself.\n\nThat probably was written in the old world where there were only 10\ncommands in each category ;-) Nevertheless I have no problem with\nthis move (and I do not think there are in-flight topics in these\nareas).\n\nThanks.\n\n>\n> Move the worktree tests to t24* to adhere to that guideline. We're\n> going to make use of the free'd up numbers in a subsequent commit.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>  t/{t2025-worktree-add.sh => t2400-worktree-add.sh}     | 0\n>  t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} | 0\n>  t/{t2027-worktree-list.sh => t2402-worktree-list.sh}   | 0\n>  3 files changed, 0 insertions(+), 0 deletions(-)\n>  rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n>  rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n>  rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n>\n> diff --git a/t/t2025-worktree-add.sh b/t/t2400-worktree-add.sh\n> similarity index 100%\n> rename from t/t2025-worktree-add.sh\n> rename to t/t2400-worktree-add.sh\n> diff --git a/t/t2026-worktree-prune.sh b/t/t2401-worktree-prune.sh\n> similarity index 100%\n> rename from t/t2026-worktree-prune.sh\n> rename to t/t2401-worktree-prune.sh\n> diff --git a/t/t2027-worktree-list.sh b/t/t2402-worktree-list.sh\n> similarity index 100%\n> rename from t/t2027-worktree-list.sh\n> rename to t/t2402-worktree-list.sh\n"},{"id":"364928","messageId":"CACsJy8AgbU9YyMHXdp=bkMncBO_Mu0FOQ4kSRkgacHzTJ0DrdA@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-2-t.gummerer@gmail.com","subject":"Re: [PATCH 1/8] move worktree tests to t24*","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T15:32:57Z","receivedAt":"2018-12-10T15:33:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 9, 2018 at 9:04 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> The 'git worktree' command used to be just another mode in 'git\n> checkout', namely 'git checkout --to'.  When the tests for the latter\n> were retrofitted for the former, the test name was adjusted, but the\n> test number was kept, even though the test is testing a different\n> command now.  t/README states: \"Second digit tells the particular\n> command we are testing.\", so 'git worktree' should have a separate\n> number just for itself.\n>\n> Move the worktree tests to t24* to adhere to that guideline. We're\n> going to make use of the free'd up numbers in a subsequent commit.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>  t/{t2025-worktree-add.sh => t2400-worktree-add.sh}     | 0\n>  t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} | 0\n>  t/{t2027-worktree-list.sh => t2402-worktree-list.sh}   | 0\n>  3 files changed, 0 insertions(+), 0 deletions(-)\n>  rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n>  rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n>  rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n\nHeh.. I did the same thing (in my unsent switch-branch/restore-files\nseries) and even used the same 24xx range :D You probably want to move\nt2028 and t2029 too (not sure if they have landed on 'master')\n-- \nDuy\n"},{"id":"364929","messageId":"CACsJy8AGerhjnT0O6vT264tND78N5cbgFREzYtdmriXERu0Jtw@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-3-t.gummerer@gmail.com","subject":"Re: [PATCH 2/8] entry: factor out unlink_entry function","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T15:49:57Z","receivedAt":"2018-12-10T15:50:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Factor out the 'unlink_entry()' function from unpack-trees.c to\n> entry.c.  It will be used in other places as well in subsequent\n> steps.\n>\n> As it's no longer a static function, also move the documentation to\n> the header file to make it more discoverable.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>  cache.h        |  5 +++++\n>  entry.c        | 15 +++++++++++++++\n>  unpack-trees.c | 19 -------------------\n>  3 files changed, 20 insertions(+), 19 deletions(-)\n>\n> diff --git a/cache.h b/cache.h\n> index ca36b44ee0..c1c953e810 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -1542,6 +1542,11 @@ struct checkout {\n>  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);\n>  extern void enable_delayed_checkout(struct checkout *state);\n>  extern int finish_delayed_checkout(struct checkout *state);\n> +/*\n> + * Unlink the last component and schedule the leading directories for\n> + * removal, such that empty directories get removed.\n> + */\n> +extern void unlink_entry(const struct cache_entry *ce);\n\nI'm torn. We try to remove 'extern' but I can see you may want to add\nit here to be consistent with others. And removing extern even from\nfunctions from entry.c only would cause some conflicts.\n\nI wonder if we should move the 'removal' variable in symlinks to\n'struct checkout' to reduce another global variable. But I guess\nthat's the problem for another day. It's not the focus of this series.\n-- \nDuy\n"},{"id":"364930","messageId":"CACsJy8DQd_DcuogF2Wnj47F6ef26L1dea7M2Yi-ESZ_naQZ=kw@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-4-t.gummerer@gmail.com","subject":"Re: [PATCH 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T15:58:10Z","receivedAt":"2018-12-10T15:58:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> 'checkout_entry()' currently only supports creating new entries in the\n> working tree, but not deleting them.  Add the ability to remove\n> entries at the same time if the entry is marked with the CE_WT_REMOVE\n> flag.\n>\n> Currently this doesn't have any effect, as the CE_WT_REMOVE flag is\n> only used in unpack-tree, however we will make use of this in a\n> subsequent step in the series.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>  entry.c | 7 +++++++\n>  1 file changed, 7 insertions(+)\n>\n> diff --git a/entry.c b/entry.c\n> index 3ec148ceee..cd1c6601b6 100644\n> --- a/entry.c\n> +++ b/entry.c\n> @@ -441,6 +441,13 @@ int checkout_entry(struct cache_entry *ce,\n>         static struct strbuf path = STRBUF_INIT;\n>         struct stat st;\n>\n> +       if (ce->ce_flags & CE_WT_REMOVE) {\n> +               if (topath)\n> +                       BUG(\"Can't remove entry to a path\");\n> +               unlink_entry(ce);\n> +               return 0;\n> +       }\n\nThis makes the path counting in nd/checkout-noisy less accurate. But\nit's not your fault of course.\n\nJunio, do you still want to merge that series down to 'next' or drop\nit? If it will be merged down, I'll keep a note and fix it once this\none lands too.\n\n> +\n>         if (topath)\n>                 return write_entry(ce, topath, state, 1);\n>\n> --\n> 2.20.0.405.gbc1bbc6f85\n>\n\n\n-- \nDuy\n"},{"id":"364931","messageId":"CACsJy8AiQvu8W4=2HLKMdg+n2HiDrcLvKPRurKvziXaJdqefRg@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-5-t.gummerer@gmail.com","subject":"Re: [PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T16:08:56Z","receivedAt":"2018-12-10T16:09:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> When marking cache entries for removal, and later removing them all at\n> once using 'remove_marked_cache_entries()', cache entries currently\n> have to be invalidated manually in the cache tree and in the untracked\n> cache.\n>\n> Add an invalidate flag to the function.  With the flag set, the\n> function will take care of invalidating the path in the cache tree and\n> in the untracked cache.\n>\n> This will be useful in a subsequent commit.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>\n> For the two current callsites, unpack-trees seems to do this\n> invalidation itself internally.\n\nI'm still a bit scared of this invalidation business in unpack-trees.\nThe thing is, we handle two separate index_state there, src_index and\nresult and invalidation has to be done on the right one (because index\nextensions are on src_index until the very end of unpack-trees;\ninvalidating on 'result' would be no-op and wrong).\nremove_marked_cache_entries() seems to be called on 'result' while\ninvalidate_ce_path() is on src_index, hm....\n\n> I don't quite understand why we don't\n> need it in split-index mode though.  I assume it's because the cache\n> tree in the main index would already have been invalidated?  I didn't\n> have much time to dig, but couldn't produce any failures with it\n> either, so I assume not invalidating paths is the right thing to do\n> here.\n\nYeah I think it's because cache-tree and untracked cache are already\nproperly invalidated. This merge base thingy is done when we load the\nindex files up, not when we write them down. The \"front\" index may\nrecord that a few paths in the base index are no longer valid and need\nto be deleted. But untracked cache and cache-tree both should have\nrecorded that same info when these paths are marked for delete at\nindex write time.\n-- \nDuy\n"},{"id":"364939","messageId":"CACsJy8BWZyFWZ70y4beCEYvjbc2+X-2K+gOiY+=toK0y3xYzKw@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-6-t.gummerer@gmail.com","subject":"Re: [PATCH 5/8] checkout: introduce --{,no-}overlay option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T16:42:34Z","receivedAt":"2018-12-10T16:43:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> @@ -302,15 +310,29 @@ static int checkout_paths(const struct checkout_opts *opts,\n>                 ce->ce_flags &= ~CE_MATCHED;\n>                 if (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n>                         continue;\n> -               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n> -                       /*\n> -                        * \"git checkout tree-ish -- path\", but this entry\n> -                        * is in the original index; it will not be checked\n> -                        * out to the working tree and it does not matter\n> -                        * if pathspec matched this entry.  We will not do\n> -                        * anything to this entry at all.\n> -                        */\n> -                       continue;\n> +               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) {\n> +                       if (!opts->overlay_mode &&\n> +                           ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {\n> +                               /*\n> +                                * \"git checkout --no-overlay <tree-ish> -- path\",\n> +                                * and the path is not in tree-ish, but is in\n> +                                * the current index, which means that it should\n> +                                * be removed.\n> +                                */\n> +                               ce->ce_flags |= CE_MATCHED | CE_REMOVE | CE_WT_REMOVE;\n> +                               continue;\n> +                       } else {\n\nIn non-overlay mode but when pathspec does not match, we come here too.\n\n> +                               /*\n> +                                * \"git checkout tree-ish -- path\", but this\n> +                                * entry is in the original index; it will not\n\nI think the missing key point in this comment block is \"..is in the\noriginal index _and it's not in tree-ish_\". In non-overlay mode, if\npathspec does not match then it's safe to ignore too. But this logic\nstarts too get to complex and hurt my brain.\n\n> +                                * be checked out to the working tree and it\n> +                                * does not matter if pathspec matched this\n> +                                * entry.  We will not do anything to this entry\n> +                                * at all.\n> +                                */\n> +                               continue;\n> +                       }\n> +               }\n>                 /*\n>                  * Either this entry came from the tree-ish we are\n>                  * checking the paths out of, or we are checking out\n\n> @@ -1266,6 +1299,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>                             \"checkout\", \"control recursive updating of submodules\",\n>                             PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n>                 OPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n> +               OPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n\nmaybe add \" (default)\" to the help string.\n\n>                 OPT_END(),\n>         };\n>\n-- \nDuy\n"},{"id":"364940","messageId":"CACsJy8CfgJ4NAnbMjBFGhRWscZxJCgxtx0QwSMw7MTjeMT4gDw@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-7-t.gummerer@gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T16:49:41Z","receivedAt":"2018-12-10T16:50:09Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Add a new --cached option to git checkout, which works only on the\n> index, but not the working tree, similar to what 'git reset <tree-ish>\n> -- <pathspec>... does.\n\nElijah wanted another mode (and I agree) that modifies worktree but\nleaves the index alone. This is most useful (or least confusing) when\nused with <tree-ish> and would be default in restore-files. I'm not\nsaying you have to implement it, but how do the new command line\noptions are designed to make sense?\n\nI guess if --cached is \"update index only\" then --no-cached goes back\nto the default \"update both worktree and index\" and we need a another\noption for \"worktree only\"? Can we have one option with three possible\nvalues (index-only, index-and-worktree, worktree-only) maybe?\n-- \nDuy\n"},{"id":"364941","messageId":"CACsJy8CjQHGANKf2Z=vJL=_ktoeXxOzQGL+VFJC4W63fzok78g@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-8-t.gummerer@gmail.com","subject":"Re: [PATCH 7/8] checkout: allow ignoring unmatched pathspec","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T16:51:14Z","receivedAt":"2018-12-10T16:51:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Currently when 'git checkout -- <pathspec>...' is invoked with\n> multiple pathspecs, where one or more of the pathspecs don't match\n> anything, checkout errors out.\n>\n> This can be inconvenient in some cases, such as when using git\n> checkout from a script.\n\nWait, should scripts go with read-tree, checkout-index or other\nplumbing commands instead?\n-- \nDuy\n"},{"id":"364942","messageId":"CACsJy8CbtK+OuhSy0490e=OjALsk8QQgDHo6q1xjTrz2R56vNA@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"Re: [PATCH 0/8] introduce no-overlay and cached mode in git checkout","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T17:06:24Z","receivedAt":"2018-12-10T17:06:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Dec 9, 2018 at 9:04 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> My hope is also that the no-overlay mode could become the new default\n> in the restore-files command Duy is currently working on.\n\nI already wrote something like that in git-restore-files.txt even\nthough the implementation is not there :D\n\nThere will be a hell of conflicts when the two series enter 'pu' (or\neven worse, when the third one to update worktree only appears) so I'm\ngoing to send the switch-branch/restore-files series out but mostly to\ngather comments and will rebase once the other series land.\n\n(Alternatively I'll split my series and let the switch-branch part\nland first, may be simpler)\n-- \nDuy\n"},{"id":"364943","messageId":"CABPp-BFaWtDiBPuGQVU_+VGQtDkemDKnvjHhz+h1sbUGssffmQ@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"Re: [PATCH 0/8] introduce no-overlay and cached mode in git checkout","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T17:18:40Z","receivedAt":"2018-12-10T17:18:56Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Dec 9, 2018 at 12:04 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Here's the series I mentioned a couple of times on the list already,\n> introducing a no-overlay mode in 'git checkout'.  The inspiration for\n> this came from Junios message in [*1*].\n>\n> Basically the idea is to also delete files when the match <pathspec>\n> in 'git checkout <tree-ish> -- <pathspec>' in the current tree, but\n> don't match <pathspec> in <tree-ish>.  The rest of the cases are\n> already properly taken care of by 'git checkout'.\n\nYes, but I'd put it a little differently:\n\n\"\"\"\nBasically, the idea is when the user run \"git checkout --no-overlay\n<tree-ish> -- <pathspec>\" that the given pathspecs should exactly\nmatch <tree-ish> after the operation completes.  This means that we\nalso want to delete files that match <pathspec> if those paths are not\nfound in <tree-ish>.\n\"\"\"\n\n...and maybe even toss in some comments about the fact that this is\nthe way git checkout should have always behaved, it just traditionally\nhasn't.  (You could also work in comments about how with this new mode\nthe user can run git diff afterward with the given commit-ish and\npathspecs and get back an empty diff, as expected, which wasn't true\nbefore.  But maybe I'm belaboring the point.)\n\n\n> The final step in the series is to actually make use of this in 'git\n> stash', which simplifies the code there a bit.  I am however happy to\n> hold off on this step until the stash-in-C series is merged, so we\n> don't delay that further.\n>\n> In addition to the no-overlay mode, we also add a --cached mode, which\n> works only on the index, thus similar to 'git reset <tree-ish> -- <pathspec>'.\n\nIf you're adding a --cached mode to make it only work on the index,\nshould there be a similar mode to allow it to only work on the working\ntree?  (I'm not as concerned with that here, but I really think the\nnew restore-files command by default should only operate on the\nworking tree, and then have options to affect the index either in\naddition or instead of the working tree.)\n\n> Actually deprecating 'git reset <tree-ish> -- <pathspec>' should come\n> later, probably not before Duy's restore-files command lands, as 'git\n> checkout --no-overlay <tree-ish> -- <pathspec>' is a bit cumbersome to\n> type compared to 'git reset <tree-ish> -- <pathspec>'.\n\nMakes sense.\n\n> My hope is also that the no-overlay mode could become the new default\n> in the restore-files command Duy is currently working on.\n\nAbsolutely, yes.  I don't want another broken command.  :-)\n\n\n> No documentation yet, as I wanted to get this out for review first.\n> I'm not familiar with most of the code I touched here, so there may\n> well be much better ways to implement some of this, that I wasn't able\n> to figure out.  I'd be very happy with some feedback around that.\n>\n> Another thing I'm not sure about is how to deal with conflicts.  In\n> the cached mode this patch series is not dealing with it at all, as\n> 'git checkout -- <pathspec>' when pathspec matches a file with\n> conflicts doesn't update the index.  For the no-overlay mode, the file\n> is removed if the corresponding stage is not found in the index.  I'm\n> however not sure this is the right thing to do in all cases?\n\nHere's how I'd go about analyzing that...\n\nIf the user passes a <tree-ish>, then the answer about what to do is\npretty obvious; the <tree-ish> didn't have conflicts, so conflicted\npaths in the index that match the pathspec should be overwritten with\nwhatever version of those paths existed in <tree-ish> (possibly\nimplying deletion of some paths).\n\nAlso, as you point out, --cached means only modify the index and not\nthe working tree; so if they specify both --cached and provide no\ntree, then they've specified a no-op.\n\nSo it's only interesting when you have conflicts in the index and\nspecify --no-overlay without a <tree-ish> or --cached.  This boils\ndown to \"how do we update the working tree to match the index, when\nthe index is conflicted?\"  A couple points to consider:\n  * This is somewhat of an edge case\n  * In the normal case --no-overlay is only different from --overlay\nbehavior for directories; it'd be nice if that extended to all cases\n  * How does this command behave without a <tree-ish> when\n--no-overlay is specified and a directory is given for a <pathspec>\nand there aren't any conflicts?  Are we being consistent with that\nbehavior?\n\n\nHowever, I think it turns out that the answer is much simpler than all\nthat initial analysis or what you say you've implemented.  Here's why:\n\nIf <pathspec> is a file which is present in both the working tree and\nthe index and it has conflicts, then \"git checkout -- <pathspec>\" will\ncurrently throw an error:\n\n$ git checkout -- subdir/counting\nerror: path 'subdir/counting' is unmerged\n\nIn fact, even if every entry in subdir/ is a path that is in both the\nindex and the working tree (so that --no-overlay and --overlay ought\nto behave the same), if any one of the files in subdir is conflicted,\nattempting to checkout the subdir will abort with this same error\nmessage and no paths will be updated at all:\n\n$ git checkout -- subdir\nerror: path 'subdir/counting' is unmerged\n\nas such, the answer with what to do with --no-overlay mode is pretty\nclear: if the <pathspec> matches _any_ path that is conflicted, simply\nthrow an error and abort the operation without making any changes at\nall.\n"},{"id":"364944","messageId":"CABPp-BE15jfe76q3hqSxnifv8MNB1e6_GDT=5=ZmTE__XuTmLw@mail.gmail.com","threadId":"49988","inReplyTo":"CACsJy8AGerhjnT0O6vT264tND78N5cbgFREzYtdmriXERu0Jtw@mail.gmail.com","subject":"Re: [PATCH 2/8] entry: factor out unlink_entry function","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T17:23:38Z","receivedAt":"2018-12-10T17:23:52Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Dec 10, 2018 at 7:50 AM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > Factor out the 'unlink_entry()' function from unpack-trees.c to\n> > entry.c.  It will be used in other places as well in subsequent\n> > steps.\n> >\n> > As it's no longer a static function, also move the documentation to\n> > the header file to make it more discoverable.\n\nI also started using unlink_entry() in another place in a local patch\nseries that I haven't submitted yet (and which I need to get back to\nat some point).  So this will help me too.  :-)\n\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >  cache.h        |  5 +++++\n> >  entry.c        | 15 +++++++++++++++\n> >  unpack-trees.c | 19 -------------------\n> >  3 files changed, 20 insertions(+), 19 deletions(-)\n> >\n> > diff --git a/cache.h b/cache.h\n> > index ca36b44ee0..c1c953e810 100644\n> > --- a/cache.h\n> > +++ b/cache.h\n> > @@ -1542,6 +1542,11 @@ struct checkout {\n> >  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);\n> >  extern void enable_delayed_checkout(struct checkout *state);\n> >  extern int finish_delayed_checkout(struct checkout *state);\n> > +/*\n> > + * Unlink the last component and schedule the leading directories for\n> > + * removal, such that empty directories get removed.\n> > + */\n> > +extern void unlink_entry(const struct cache_entry *ce);\n>\n> I'm torn. We try to remove 'extern' but I can see you may want to add\n> it here to be consistent with others. And removing extern even from\n> functions from entry.c only would cause some conflicts.\n>\n> I wonder if we should move the 'removal' variable in symlinks to\n> 'struct checkout' to reduce another global variable. But I guess\n> that's the problem for another day. It's not the focus of this series.\n\n\"move the 'removal' variable in symlinks\"?  I'm having a really hard\ntime parsing that phrase and the sentence it's embedded in.  Could you\nreword for me Duy?\n"},{"id":"364945","messageId":"CACsJy8BgceLwH71SkkA0n_etrOrC8ucGBpkK2+RB+PU3F=0RgQ@mail.gmail.com","threadId":"49988","inReplyTo":"CABPp-BE15jfe76q3hqSxnifv8MNB1e6_GDT=5=ZmTE__XuTmLw@mail.gmail.com","subject":"Re: [PATCH 2/8] entry: factor out unlink_entry function","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T17:27:46Z","receivedAt":"2018-12-10T17:28:14Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Dec 10, 2018 at 6:23 PM Elijah Newren <newren@gmail.com> wrote:\n> > I wonder if we should move the 'removal' variable in symlinks to\n> > 'struct checkout' to reduce another global variable. But I guess\n> > that's the problem for another day. It's not the focus of this series.\n>\n> \"move the 'removal' variable in symlinks\"?  I'm having a really hard\n> time parsing that phrase and the sentence it's embedded in.  Could you\n> reword for me Duy?\n\nSorry s/in symlinks/&.c/. There's a global variable named 'removal' in\nsymlinks.c which is used by schedule_dir_for_removal() and this\nfunction in turn is used by unlink_entry().\n-- \nDuy\n"},{"id":"364946","messageId":"CABPp-BHO7UmAm14HWf2tc+SVEZuWBqyvvrQg625fDsiDYPEL8g@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-4-t.gummerer@gmail.com","subject":"Re: [PATCH 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T17:49:17Z","receivedAt":"2018-12-10T17:49:33Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Dec 9, 2018 at 12:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> 'checkout_entry()' currently only supports creating new entries in the\n> working tree, but not deleting them.  Add the ability to remove\n> entries at the same time if the entry is marked with the CE_WT_REMOVE\n> flag.\n>\n> Currently this doesn't have any effect, as the CE_WT_REMOVE flag is\n> only used in unpack-tree, however we will make use of this in a\n> subsequent step in the series.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>  entry.c | 7 +++++++\n>  1 file changed, 7 insertions(+)\n>\n> diff --git a/entry.c b/entry.c\n> index 3ec148ceee..cd1c6601b6 100644\n> --- a/entry.c\n> +++ b/entry.c\n> @@ -441,6 +441,13 @@ int checkout_entry(struct cache_entry *ce,\n>         static struct strbuf path = STRBUF_INIT;\n>         struct stat st;\n>\n> +       if (ce->ce_flags & CE_WT_REMOVE) {\n> +               if (topath)\n> +                       BUG(\"Can't remove entry to a path\");\n\nMinor nit: This error message is kinda hard to parse, for someone not\nthat familiar with all the *_entry functions, like myself.  Maybe add\na comment before this line:\n    /* No content and thus no path to create, so we have no pathname\nto return */\nor reword the error slightly?  Or maybe it's fine and I was just\nconfused from lack of code familiarity, but I'll throw it out there\nsince I stumbled on it a bit.\n\n> +               unlink_entry(ce);\n> +               return 0;\n> +       }\n> +\n>         if (topath)\n>                 return write_entry(ce, topath, state, 1);\n>\n> --\n> 2.20.0.405.gbc1bbc6f85\n"},{"id":"364953","messageId":"CABPp-BEkeRa7jOkDcNNpZMY9J9JmNGtMKjZeNv8i_u7jUFihcw@mail.gmail.com","threadId":"49988","inReplyTo":"CACsJy8AiQvu8W4=2HLKMdg+n2HiDrcLvKPRurKvziXaJdqefRg@mail.gmail.com","subject":"Re: [PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T18:09:26Z","receivedAt":"2018-12-10T18:09:41Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Dec 10, 2018 at 8:09 AM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > When marking cache entries for removal, and later removing them all at\n> > once using 'remove_marked_cache_entries()', cache entries currently\n> > have to be invalidated manually in the cache tree and in the untracked\n> > cache.\n> >\n> > Add an invalidate flag to the function.  With the flag set, the\n> > function will take care of invalidating the path in the cache tree and\n> > in the untracked cache.\n> >\n> > This will be useful in a subsequent commit.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >\n> > For the two current callsites, unpack-trees seems to do this\n> > invalidation itself internally.\n>\n> I'm still a bit scared of this invalidation business in unpack-trees.\n> The thing is, we handle two separate index_state there, src_index and\n> result and invalidation has to be done on the right one (because index\n> extensions are on src_index until the very end of unpack-trees;\n> invalidating on 'result' would be no-op and wrong).\n> remove_marked_cache_entries() seems to be called on 'result' while\n> invalidate_ce_path() is on src_index, hm....\n\nIs Thomas avoiding problems here simply because merge is the only\ncaller of unpack_trees with src_index != dst_index?  Or does src_index\n== dst_index for checkout not actually help?\n\nIf that does help with the checkout case, then allow me to find a\ndifferent way to muddy the waters...  I think I might want to make use\nof this function in the merge machinery at some point, so I either\nneed to figure out how to convince you to verify if all this cache\ntree invalidation stuff is sane, or somehow figure out all the\ncache_tree stuff stuff myself so I can figure out what is right here.\n:-)\n\n> > I don't quite understand why we don't\n> > need it in split-index mode though.  I assume it's because the cache\n> > tree in the main index would already have been invalidated?  I didn't\n> > have much time to dig, but couldn't produce any failures with it\n> > either, so I assume not invalidating paths is the right thing to do\n> > here.\n>\n> Yeah I think it's because cache-tree and untracked cache are already\n> properly invalidated. This merge base thingy is done when we load the\n> index files up, not when we write them down. The \"front\" index may\n> record that a few paths in the base index are no longer valid and need\n> to be deleted. But untracked cache and cache-tree both should have\n> recorded that same info when these paths are marked for delete at\n> index write time.\n"},{"id":"364954","messageId":"CACsJy8BG5ri=UMeOPqLTqxcOYqPsc9BdY4pxgQA8pfb+rE1MyA@mail.gmail.com","threadId":"49988","inReplyTo":"CABPp-BEkeRa7jOkDcNNpZMY9J9JmNGtMKjZeNv8i_u7jUFihcw@mail.gmail.com","subject":"Re: [PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T18:19:21Z","receivedAt":"2018-12-10T18:19:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Dec 10, 2018 at 7:09 PM Elijah Newren <newren@gmail.com> wrote:\n> > > For the two current callsites, unpack-trees seems to do this\n> > > invalidation itself internally.\n> >\n> > I'm still a bit scared of this invalidation business in unpack-trees.\n> > The thing is, we handle two separate index_state there, src_index and\n> > result and invalidation has to be done on the right one (because index\n> > extensions are on src_index until the very end of unpack-trees;\n> > invalidating on 'result' would be no-op and wrong).\n> > remove_marked_cache_entries() seems to be called on 'result' while\n> > invalidate_ce_path() is on src_index, hm....\n>\n> Is Thomas avoiding problems here simply because merge is the only\n> caller of unpack_trees with src_index != dst_index?  Or does src_index\n> == dst_index for checkout not actually help?\n\nI think it would not help. 'result' is a temporary index where we copy\nthings to (and it does not have anything from the beginning). If you\ninvalidate stuff in there, you invalidate nothing, regardless whether\ndst_index == src_index.\n\n> If that does help with the checkout case, then allow me to find a\n> different way to muddy the waters...  I think I might want to make use\n> of this function in the merge machinery at some point, so I either\n> need to figure out how to convince you to verify if all this cache\n> tree invalidation stuff is sane, or somehow figure out all the\n> cache_tree stuff stuff myself so I can figure out what is right here.\n> :-)\n\nI'm not the unpack-trees man (I think that would still be Junio). And\nI'm not saying it's sane either. I think it's just some leftover\nthings since Linus split \"the index\" in unpack-tree operation to\n'src', 'result' and 'dst' many years ago and nobody was brave enough\nto clean it up (then I piled on with untracked cache and split index,\nbut I did not see it clearly either). That person could be you ;-)\n-- \nDuy\n"},{"id":"364955","messageId":"CABPp-BEk+7n2wcbjETishqnMBs5DGrTEvD7gahLtEj5bZ2AYvA@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-6-t.gummerer@gmail.com","subject":"Re: [PATCH 5/8] checkout: introduce --{,no-}overlay option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T18:19:40Z","receivedAt":"2018-12-10T18:19:55Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Dec 9, 2018 at 12:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Currently 'git checkout' is defined as an overlay operation, which\n> means that if in 'git checkout <tree-ish> -- [<pathspec>]' we have an\n> entry in the index that matches <pathspec>, but that doesn't exist in\n> <tree-ish>, that entry will not be removed from the index or the\n> working tree.\n>\n> Introduce a new --{,no-}overlay option, which allows using 'git\n> checkout' in non-overlay mode, thus removing files from the working\n> tree if they do not exist in <tree-ish> but match <pathspec>.\n>\n> Note that 'git checkout -p <tree-ish> -- [<pathspec>]' already works\n> this way, so no changes are needed for the patch mode.  We disallow\n> 'git checkout --overlay -p' to avoid confusing users who would expect\n> to be able to force overlay mode in 'git checkout -p' this way.\n\nWhoa...that's interesting.  To me, that argues even further that the\ntraditional checkout behavior was wrong all along and the choice of\n--overlay vs. --no-overlay in the original implementation was a total\noversight.  I'm really tempted to say that --no-overlay should just be\nthe default in checkout too...but maybe that's too high a hill to\nclimb, at least for now.\n\nMaking --overlap and -p incompatible is a reasonable first step.  But\nyou should probably add a comment to the -p option documentation that\nit implies --no-overlay.\n\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>  builtin/checkout.c             | 64 +++++++++++++++++++++++++++-------\n>  t/t2025-checkout-no-overlay.sh | 47 +++++++++++++++++++++++++\n>  t/t9902-completion.sh          |  1 +\n>  3 files changed, 99 insertions(+), 13 deletions(-)\n>  create mode 100755 t/t2025-checkout-no-overlay.sh\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index acdafc6e4c..0aef35bbc4 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -44,6 +44,7 @@ struct checkout_opts {\n>         int ignore_skipworktree;\n>         int ignore_other_worktrees;\n>         int show_progress;\n> +       int overlay_mode;\n>         /*\n>          * If new checkout options are added, skip_merge_working_tree\n>          * should be updated accordingly.\n> @@ -132,7 +133,8 @@ static int skip_same_name(const struct cache_entry *ce, int pos)\n>         return pos;\n>  }\n>\n> -static int check_stage(int stage, const struct cache_entry *ce, int pos)\n> +static int check_stage(int stage, const struct cache_entry *ce, int pos,\n> +                      int overlay_mode)\n>  {\n>         while (pos < active_nr &&\n>                !strcmp(active_cache[pos]->name, ce->name)) {\n> @@ -140,6 +142,8 @@ static int check_stage(int stage, const struct cache_entry *ce, int pos)\n>                         return 0;\n>                 pos++;\n>         }\n> +       if (!overlay_mode)\n> +               return 0;\n>         if (stage == 2)\n>                 return error(_(\"path '%s' does not have our version\"), ce->name);\n>         else\n> @@ -165,7 +169,7 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)\n>  }\n>\n>  static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n> -                         const struct checkout *state)\n> +                         const struct checkout *state, int overlay_mode)\n>  {\n>         while (pos < active_nr &&\n>                !strcmp(active_cache[pos]->name, ce->name)) {\n> @@ -173,6 +177,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n>                         return checkout_entry(active_cache[pos], state, NULL);\n>                 pos++;\n>         }\n> +       if (!overlay_mode) {\n> +               unlink_entry(ce);\n> +               return 0;\n> +       }\n>         if (stage == 2)\n>                 return error(_(\"path '%s' does not have our version\"), ce->name);\n>         else\n> @@ -302,15 +310,29 @@ static int checkout_paths(const struct checkout_opts *opts,\n>                 ce->ce_flags &= ~CE_MATCHED;\n>                 if (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n>                         continue;\n> -               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n> -                       /*\n> -                        * \"git checkout tree-ish -- path\", but this entry\n> -                        * is in the original index; it will not be checked\n> -                        * out to the working tree and it does not matter\n> -                        * if pathspec matched this entry.  We will not do\n> -                        * anything to this entry at all.\n> -                        */\n> -                       continue;\n> +               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) {\n> +                       if (!opts->overlay_mode &&\n> +                           ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {\n> +                               /*\n> +                                * \"git checkout --no-overlay <tree-ish> -- path\",\n> +                                * and the path is not in tree-ish, but is in\n> +                                * the current index, which means that it should\n> +                                * be removed.\n> +                                */\n> +                               ce->ce_flags |= CE_MATCHED | CE_REMOVE | CE_WT_REMOVE;\n> +                               continue;\n> +                       } else {\n> +                               /*\n> +                                * \"git checkout tree-ish -- path\", but this\n> +                                * entry is in the original index; it will not\n> +                                * be checked out to the working tree and it\n> +                                * does not matter if pathspec matched this\n> +                                * entry.  We will not do anything to this entry\n> +                                * at all.\n> +                                */\n> +                               continue;\n> +                       }\n> +               }\n>                 /*\n>                  * Either this entry came from the tree-ish we are\n>                  * checking the paths out of, or we are checking out\n> @@ -348,7 +370,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n>                         if (opts->force) {\n>                                 warning(_(\"path '%s' is unmerged\"), ce->name);\n>                         } else if (opts->writeout_stage) {\n> -                               errs |= check_stage(opts->writeout_stage, ce, pos);\n> +                               errs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode);\n>                         } else if (opts->merge) {\n>                                 errs |= check_stages((1<<2) | (1<<3), ce, pos);\n>                         } else {\n> @@ -375,12 +397,14 @@ static int checkout_paths(const struct checkout_opts *opts,\n>                                 continue;\n>                         }\n>                         if (opts->writeout_stage)\n> -                               errs |= checkout_stage(opts->writeout_stage, ce, pos, &state);\n> +                               errs |= checkout_stage(opts->writeout_stage, ce, pos, &state, opts->overlay_mode);\n>                         else if (opts->merge)\n>                                 errs |= checkout_merged(pos, &state);\n>                         pos = skip_same_name(ce, pos) - 1;\n>                 }\n>         }\n> +       remove_marked_cache_entries(&the_index, 1);\n> +       remove_scheduled_dirs();\n>         errs |= finish_delayed_checkout(&state);\n>\n>         if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))\n> @@ -542,6 +566,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,\n>          * opts->show_progress only impacts output so doesn't require a merge\n>          */\n>\n> +       /*\n> +        * opts->overlay_mode cannot be used with switching branches so is\n> +        * not tested here\n> +        */\n> +\n>         /*\n>          * If we aren't creating a new branch any changes or updates will\n>          * happen in the existing branch.  Since that could only be updating\n> @@ -1178,6 +1207,10 @@ static int checkout_branch(struct checkout_opts *opts,\n>                 die(_(\"'%s' cannot be used with switching branches\"),\n>                     \"--patch\");\n>\n> +       if (!opts->overlay_mode)\n> +               die(_(\"'%s' cannot be used with switching branches\"),\n> +                   \"--no-overlay\");\n> +\n>         if (opts->writeout_stage)\n>                 die(_(\"'%s' cannot be used with switching branches\"),\n>                     \"--ours/--theirs\");\n> @@ -1266,6 +1299,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>                             \"checkout\", \"control recursive updating of submodules\",\n>                             PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n>                 OPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n> +               OPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n>                 OPT_END(),\n>         };\n>\n> @@ -1274,6 +1308,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>         opts.overwrite_ignore = 1;\n>         opts.prefix = prefix;\n>         opts.show_progress = -1;\n> +       opts.overlay_mode = -1;\n>\n>         git_config(git_checkout_config, &opts);\n>\n> @@ -1297,6 +1332,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>         if ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)\n>                 die(_(\"-b, -B and --orphan are mutually exclusive\"));\n>\n> +       if (opts.overlay_mode == 1 && opts.patch_mode)\n> +               die(_(\"-p and --overlay are mutually exclusive\"));\n> +\n>         /*\n>          * From here on, new_branch will contain the branch to be checked out,\n>          * and new_branch_force and new_orphan_branch will tell us which one of\n> diff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh\n> new file mode 100755\n> index 0000000000..3575321382\n> --- /dev/null\n> +++ b/t/t2025-checkout-no-overlay.sh\n> @@ -0,0 +1,47 @@\n> +#!/bin/sh\n> +\n> +test_description='checkout --no-overlay <tree-ish> -- <pathspec>'\n> +\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'setup' '\n> +       git commit --allow-empty -m \"initial\"\n> +'\n> +\n> +test_expect_success 'checkout --no-overlay deletes files not in <tree>' '\n> +       >file &&\n> +       mkdir dir &&\n> +       >dir/file1 &&\n> +       git add file dir/file1 &&\n> +       git checkout --no-overlay HEAD -- file &&\n> +       test_path_is_missing file &&\n> +       test_path_is_file dir/file1\n> +'\n> +\n> +test_expect_success 'checkout --no-overlay removing last file from directory' '\n> +       git checkout --no-overlay HEAD -- dir/file1 &&\n> +       test_path_is_missing dir\n> +'\n> +\n> +test_expect_success 'checkout -p --overlay is disallowed' '\n> +       test_must_fail git checkout -p --overlay HEAD 2>actual &&\n> +       test_i18ngrep \"fatal: -p and --overlay are mutually exclusive\" actual\n> +'\n> +\n> +test_expect_success '--no-overlay --theirs with M/D conflict deletes file' '\n> +       test_commit file1 file1 &&\n> +       test_commit file2 file2 &&\n> +       git rm --cached file1 &&\n> +       echo 1234 >file1 &&\n> +       F1=$(git rev-parse HEAD:file1) &&\n> +       F2=$(git rev-parse HEAD:file2) &&\n> +       {\n> +               echo \"100644 $F1 1      file1\" &&\n> +               echo \"100644 $F2 2      file1\"\n> +       } | git update-index --index-info &&\n> +       test_path_is_file file1 &&\n> +       git checkout --theirs --no-overlay -- file1 &&\n> +       test_path_is_missing file1\n> +'\n> +\n> +test_done\n> diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\n> index 175f83d704..a3fd9a9630 100755\n> --- a/t/t9902-completion.sh\n> +++ b/t/t9902-completion.sh\n> @@ -1436,6 +1436,7 @@ test_expect_success 'double dash \"git checkout\"' '\n>         --progress Z\n>         --no-quiet Z\n>         --no-... Z\n> +       --overlay Z\n>         EOF\n>  '\n>\n> --\n> 2.20.0.405.gbc1bbc6f85\n>\n"},{"id":"364956","messageId":"CABPp-BH7CuNy-6wg1jnxytuwEF9Vw=8Y0N8dUhdCJJbyps2kyw@mail.gmail.com","threadId":"49988","inReplyTo":"CACsJy8BG5ri=UMeOPqLTqxcOYqPsc9BdY4pxgQA8pfb+rE1MyA@mail.gmail.com","subject":"Re: [PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T18:25:05Z","receivedAt":"2018-12-10T18:25:20Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Dec 10, 2018 at 10:19 AM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Mon, Dec 10, 2018 at 7:09 PM Elijah Newren <newren@gmail.com> wrote:\n> > > > For the two current callsites, unpack-trees seems to do this\n> > > > invalidation itself internally.\n> > >\n> > > I'm still a bit scared of this invalidation business in unpack-trees.\n> > > The thing is, we handle two separate index_state there, src_index and\n> > > result and invalidation has to be done on the right one (because index\n> > > extensions are on src_index until the very end of unpack-trees;\n> > > invalidating on 'result' would be no-op and wrong).\n> > > remove_marked_cache_entries() seems to be called on 'result' while\n> > > invalidate_ce_path() is on src_index, hm....\n> >\n> > Is Thomas avoiding problems here simply because merge is the only\n> > caller of unpack_trees with src_index != dst_index?  Or does src_index\n> > == dst_index for checkout not actually help?\n>\n> I think it would not help. 'result' is a temporary index where we copy\n> things to (and it does not have anything from the beginning). If you\n> invalidate stuff in there, you invalidate nothing, regardless whether\n> dst_index == src_index.\n>\n> > If that does help with the checkout case, then allow me to find a\n> > different way to muddy the waters...  I think I might want to make use\n> > of this function in the merge machinery at some point, so I either\n> > need to figure out how to convince you to verify if all this cache\n> > tree invalidation stuff is sane, or somehow figure out all the\n> > cache_tree stuff stuff myself so I can figure out what is right here.\n> > :-)\n>\n> I'm not the unpack-trees man (I think that would still be Junio). And\n> I'm not saying it's sane either. I think it's just some leftover\n> things since Linus split \"the index\" in unpack-tree operation to\n> 'src', 'result' and 'dst' many years ago and nobody was brave enough\n> to clean it up (then I piled on with untracked cache and split index,\n> but I did not see it clearly either). That person could be you ;-)\n\nHmm, might make a good New Year's resolution: Enter the abyss, find\nout if one can return from it...  or maybe I could just sanely run\naway screaming.  We'll see.\n"},{"id":"364957","messageId":"CACsJy8CR2p4784PxX2o+t4QcgyiU=QoiqLeB5o86cdyd5_fHEA@mail.gmail.com","threadId":"49988","inReplyTo":"CABPp-BH7CuNy-6wg1jnxytuwEF9Vw=8Y0N8dUhdCJJbyps2kyw@mail.gmail.com","subject":"Re: [PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T18:33:39Z","receivedAt":"2018-12-10T18:34:08Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Dec 10, 2018 at 7:25 PM Elijah Newren <newren@gmail.com> wrote:\n> > I'm not the unpack-trees man (I think that would still be Junio). And\n> > I'm not saying it's sane either. I think it's just some leftover\n> > things since Linus split \"the index\" in unpack-tree operation to\n> > 'src', 'result' and 'dst' many years ago and nobody was brave enough\n> > to clean it up (then I piled on with untracked cache and split index,\n> > but I did not see it clearly either). That person could be you ;-)\n>\n> Hmm, might make a good New Year's resolution: Enter the abyss, find\n> out if one can return from it...  or maybe I could just sanely run\n> away screaming.  We'll see.\n\nI'm getting off topic. But my new years resolution would be optimize\nfor the case where src_index == dst_index, which is somewhat ironic\nbecause we used to do everything in the same index, but it was a messy\nmess and had to be split up.\n-- \nDuy\n"},{"id":"364958","messageId":"CACsJy8B63jwP4115B8vdTU+tmij8gA7jw-D5iS2Litph9jE1nQ@mail.gmail.com","threadId":"49988","inReplyTo":"CABPp-BFaWtDiBPuGQVU_+VGQtDkemDKnvjHhz+h1sbUGssffmQ@mail.gmail.com","subject":"Re: [PATCH 0/8] introduce no-overlay and cached mode in git checkout","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-10T18:37:08Z","receivedAt":"2018-12-10T18:37:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Dec 10, 2018 at 6:18 PM Elijah Newren <newren@gmail.com> wrote:\n> > The final step in the series is to actually make use of this in 'git\n> > stash', which simplifies the code there a bit.  I am however happy to\n> > hold off on this step until the stash-in-C series is merged, so we\n> > don't delay that further.\n> >\n> > In addition to the no-overlay mode, we also add a --cached mode, which\n> > works only on the index, thus similar to 'git reset <tree-ish> -- <pathspec>'.\n>\n> If you're adding a --cached mode to make it only work on the index,\n> should there be a similar mode to allow it to only work on the working\n> tree?  (I'm not as concerned with that here, but I really think the\n> new restore-files command by default should only operate on the\n> working tree, and then have options to affect the index either in\n> addition or instead of the working tree.)\n\nIn the context of restore-files, --target=<worktree|index|both> is a\nvery good candidate because \"restore-files --from=foo --target=index\"\nis almost like saying \"restore files in the index from \"foo\"\". For\ncheckout, probably not as good. But then we can have different option\nnames for the two commands. So if \"git checkout\" is going to never\nhave \"update worktree only\" mode, then --cached is a still good way to\ngo.\n-- \nDuy\n"},{"id":"364959","messageId":"CABPp-BEyRNniNFBuMMFXjvuSz9RtP6R7TeBAWDJO+Y70oe7CBA@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-7-t.gummerer@gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T18:42:44Z","receivedAt":"2018-12-10T18:43:00Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Dec 9, 2018 at 12:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Add a new --cached option to git checkout, which works only on the\n> index, but not the working tree, similar to what 'git reset <tree-ish>\n> -- <pathspec>... does.  Indeed the tests are adapted from the 'git\n> reset' tests.\n>\n> In the longer term the idea is to potentially deprecate 'git reset\n> <tree-ish> -- <pathspec>...', so the 'git reset' command becomes only\n> about re-pointing the HEAD, and not also about copying entries from\n> <tree-ish> to the index.\n>\n> Note that 'git checkout' by default works in overlay mode, meaning\n> files that match the pathspec that don't exist in <tree-ish>, but\n> exist in the index would not be removed.  'git checkout --no-overlay\n> --cached' can be used to get the same behaviour as 'git reset\n> <tree-ish> -- <pathspec>'.\n\nI think this argues _even more_ that --no-overlay should be the\ndefault.  Your series is valuable even if we don't push on that, I'm\njust being noisy about what I think would be an even better world.\n\nAlso, I don't think I've mentioned it yet, but I'm really excited\nabout this series and what you're doing.  It's super cool.  (Which I\nexpected when I saw the description of the desired behavior, but I'm\nalso liking and contemplating re-using some code...)\n\n> One thing this patch doesn't currently deal with is conflicts.\n> Currently 'git checkout --{ours,theirs} -- <file-with-conflicts>'\n> doesn't do anything with the index, so the --cached option just\n> mirrors that behaviour.  But given it doesn't even deal with\n> conflicts, the '--cached' option doesn't make much sense when no\n> <tree-ish> is given.  As it operates only on the index, it's always a\n> no-op if no tree-ish is given.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>\n> Maybe we can just disallow --cached without <tree-ish> given for now,\n> and possibly later allow it with some different behaviour for\n> conflicts, not sure what the best way forward here is.  We can also\n> just make it update the index as appropriate, and have it behave\n> different than 'git checkout' curerntly does when handling conflicts?\n\nHuh?\n  \"git checkout -- <path>\"\nmeans update <path> from the index, meaning the index is left alone\n(it's the source) and only the working tree is touched.\n\nWhen you add a flag named --cached to only update the index and not\nthe working tree, then the index becomes the sole destination.\n\nNow we combine: no tree is specified means the index is the source of\nthe writing, and --cached being specified means the index is the sole\ndestination of the writing.  Thus, you have a no-op.  If the user\nspecifies --cached and no tree, you should immediately exit with a\nmessage along the lines of \"Nothing to do; no tree given and --cached\nspecified.\"  The presence of conflicts seems completely irrelevant to\nme here.\n\n>  builtin/checkout.c         |  26 ++++++++--\n>  t/t2016-checkout-patch.sh  |   8 +++\n>  t/t2026-checkout-cached.sh | 103 +++++++++++++++++++++++++++++++++++++\n>  t/t9902-completion.sh      |   1 +\n>  4 files changed, 135 insertions(+), 3 deletions(-)\n>  create mode 100755 t/t2026-checkout-cached.sh\n>\n> diff --git a/builtin/checkout.c b/builtin/checkout.c\n> index 0aef35bbc4..6ba85e9de5 100644\n> --- a/builtin/checkout.c\n> +++ b/builtin/checkout.c\n> @@ -45,6 +45,7 @@ struct checkout_opts {\n>         int ignore_other_worktrees;\n>         int show_progress;\n>         int overlay_mode;\n> +       int cached;\n>         /*\n>          * If new checkout options are added, skip_merge_working_tree\n>          * should be updated accordingly.\n> @@ -288,6 +289,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n>                 die(_(\"Cannot update paths and switch to branch '%s' at the same time.\"),\n>                     opts->new_branch);\n>\n> +       if (opts->patch_mode && opts->cached)\n> +               return run_add_interactive(revision, \"--patch=reset\",\n> +                                          &opts->pathspec);\n> +\n>         if (opts->patch_mode)\n>                 return run_add_interactive(revision, \"--patch=checkout\",\n>                                            &opts->pathspec);\n> @@ -319,7 +324,9 @@ static int checkout_paths(const struct checkout_opts *opts,\n>                                  * the current index, which means that it should\n>                                  * be removed.\n>                                  */\n> -                               ce->ce_flags |= CE_MATCHED | CE_REMOVE | CE_WT_REMOVE;\n> +                               ce->ce_flags |= CE_MATCHED | CE_REMOVE;\n> +                               if (!opts->cached)\n> +                                       ce->ce_flags |= CE_WT_REMOVE;\n>                                 continue;\n>                         } else {\n>                                 /*\n> @@ -392,6 +399,9 @@ static int checkout_paths(const struct checkout_opts *opts,\n>         for (pos = 0; pos < active_nr; pos++) {\n>                 struct cache_entry *ce = active_cache[pos];\n>                 if (ce->ce_flags & CE_MATCHED) {\n> +                       if (opts->cached) {\n> +                               continue;\n> +                       }\n>                         if (!ce_stage(ce)) {\n>                                 errs |= checkout_entry(ce, &state, NULL);\n>                                 continue;\n> @@ -571,6 +581,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,\n>          * not tested here\n>          */\n>\n> +       /*\n> +        * opts->cached cannot be used with switching branches so is\n> +        * not tested here\n> +        */\n> +\n>         /*\n>          * If we aren't creating a new branch any changes or updates will\n>          * happen in the existing branch.  Since that could only be updating\n> @@ -1207,9 +1222,13 @@ static int checkout_branch(struct checkout_opts *opts,\n>                 die(_(\"'%s' cannot be used with switching branches\"),\n>                     \"--patch\");\n>\n> -       if (!opts->overlay_mode)\n> +       if (opts->overlay_mode != -1)\n> +               die(_(\"'%s' cannot be used with switching branches\"),\n> +                   \"--overlay/--no-overlay\");\n> +\n> +       if (opts->cached)\n>                 die(_(\"'%s' cannot be used with switching branches\"),\n> -                   \"--no-overlay\");\n> +                   \"--cached\");\n>\n>         if (opts->writeout_stage)\n>                 die(_(\"'%s' cannot be used with switching branches\"),\n> @@ -1300,6 +1319,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n>                             PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n>                 OPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n>                 OPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n> +               OPT_BOOL(0, \"cached\", &opts.cached, N_(\"work on the index only\")),\n>                 OPT_END(),\n>         };\n>\n> diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh\n> index 47aeb0b167..e8774046e0 100755\n> --- a/t/t2016-checkout-patch.sh\n> +++ b/t/t2016-checkout-patch.sh\n> @@ -108,6 +108,14 @@ test_expect_success PERL 'path limiting works: foo inside dir' '\n>         verify_state dir/foo head head\n>  '\n>\n> +test_expect_success PERL 'git checkout --cached -p' '\n> +       set_and_save_state dir/foo work work &&\n> +       test_write_lines n y | git checkout --cached -p >output &&\n> +       verify_state dir/foo work head &&\n> +       verify_saved_state bar &&\n> +       test_i18ngrep \"Unstage\" output\n> +'\n> +\n>  test_expect_success PERL 'none of this moved HEAD' '\n>         verify_saved_head\n>  '\n> diff --git a/t/t2026-checkout-cached.sh b/t/t2026-checkout-cached.sh\n> new file mode 100755\n> index 0000000000..1b66192727\n> --- /dev/null\n> +++ b/t/t2026-checkout-cached.sh\n> @@ -0,0 +1,103 @@\n> +#!/bin/sh\n> +\n> +test_description='checkout --cached <pathspec>'\n> +\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'checkout --cached <pathspec>' '\n> +       echo 1 >file1 &&\n> +       echo 2 >file2 &&\n> +       git add file1 file2 &&\n> +       test_tick &&\n> +       git commit -m files &&\n> +       git rm file2 &&\n> +       echo 3 >file3 &&\n> +       echo 4 >file1 &&\n> +       git add file1 file3 &&\n> +       git checkout --cached HEAD -- file1 file2 &&\n> +       test_must_fail git diff --quiet &&\n> +\n> +       cat >expect <<-\\EOF &&\n> +       diff --git a/file1 b/file1\n> +       index d00491f..b8626c4 100644\n> +       --- a/file1\n> +       +++ b/file1\n> +       @@ -1 +1 @@\n> +       -1\n> +       +4\n> +       diff --git a/file2 b/file2\n> +       deleted file mode 100644\n> +       index 0cfbf08..0000000\n> +       --- a/file2\n> +       +++ /dev/null\n> +       @@ -1 +0,0 @@\n> +       -2\n> +       EOF\n> +       git diff >actual &&\n> +       test_cmp expect actual &&\n> +\n> +       cat >expect <<-\\EOF &&\n> +       diff --git a/file3 b/file3\n> +       new file mode 100644\n> +       index 0000000..00750ed\n> +       --- /dev/null\n> +       +++ b/file3\n> +       @@ -0,0 +1 @@\n> +       +3\n> +       EOF\n> +       git diff --cached >actual &&\n> +       test_cmp expect actual\n> +'\n> +\n> +test_expect_success 'checking out an unmodified path is a no-op' '\n> +       git reset --hard &&\n> +       git checkout --cached HEAD -- file1 &&\n> +       git diff-files --exit-code &&\n> +       git diff-index --cached --exit-code HEAD\n> +'\n> +\n> +test_expect_success 'checking out specific path that is unmerged' '\n> +       test_commit file3 file3 &&\n> +       git rm --cached file2 &&\n> +       echo 1234 >file2 &&\n> +       F1=$(git rev-parse HEAD:file1) &&\n> +       F2=$(git rev-parse HEAD:file2) &&\n> +       F3=$(git rev-parse HEAD:file3) &&\n> +       {\n> +               echo \"100644 $F1 1      file2\" &&\n> +               echo \"100644 $F2 2      file2\" &&\n> +               echo \"100644 $F3 3      file2\"\n> +       } | git update-index --index-info &&\n> +       git ls-files -u &&\n> +       git checkout --cached HEAD file2 &&\n> +       test_must_fail git diff --quiet &&\n> +       git diff-index --exit-code --cached HEAD\n> +'\n> +\n> +test_expect_success '--cached without --no-overlay does not remove entry from index' '\n> +       test_must_fail git checkout --cached HEAD^ file3 &&\n> +       git ls-files --error-unmatch -- file3\n> +'\n> +\n> +test_expect_success 'file is removed from the index with --no-overlay' '\n> +       git checkout --cached --no-overlay HEAD^ file3 &&\n> +       test_path_is_file file3 &&\n> +       test_must_fail git ls-files --error-unmatch -- file3\n> +'\n> +\n> +test_expect_success 'test checkout --cached --no-overlay at given paths' '\n> +       mkdir sub &&\n> +       >sub/file1 &&\n> +       >sub/file2 &&\n> +       git update-index --add sub/file1 sub/file2 &&\n> +       T=$(git write-tree) &&\n> +       git checkout --cached --no-overlay HEAD sub/file2 &&\n> +       test_must_fail git diff --quiet &&\n> +       U=$(git write-tree) &&\n\nDo we need to worry at all about losing the exit status of write-tree\nin either invocation?  In particular, if the second one for U fails\nsomehow, we'd end up with $U being a blank string and we'd still\nprobably get \"$T\" != \"$U\" below.\n\nYou also had some rev-parse invocations hidden in a sub-shell in both\nthis patch and patch 5, but subsequent commands relied on non-empty\noutput out of those, so I figured those were fine.  This one might be\ntoo, but I thought I'd at least mention it.\n\n> +       echo \"$T\" &&\n> +       echo \"$U\" &&\n> +       test_must_fail git diff-index --cached --exit-code \"$T\" &&\n> +       test \"$T\" != \"$U\"\n> +'\n> +\n> +test_done\n> diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\n> index a3fd9a9630..cbc304ace8 100755\n> --- a/t/t9902-completion.sh\n> +++ b/t/t9902-completion.sh\n> @@ -1437,6 +1437,7 @@ test_expect_success 'double dash \"git checkout\"' '\n>         --no-quiet Z\n>         --no-... Z\n>         --overlay Z\n> +       --cached Z\n>         EOF\n>  '\n>\n> --\n> 2.20.0.405.gbc1bbc6f85\n"},{"id":"364964","messageId":"CABPp-BE-O-zMyndzqtyy9L6JM5HYAzOcA-Y9ffP_4ZMhm1FqcA@mail.gmail.com","threadId":"49988","inReplyTo":"CACsJy8CR2p4784PxX2o+t4QcgyiU=QoiqLeB5o86cdyd5_fHEA@mail.gmail.com","subject":"Re: [PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T18:47:09Z","receivedAt":"2018-12-10T18:47:26Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Dec 10, 2018 at 10:34 AM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Mon, Dec 10, 2018 at 7:25 PM Elijah Newren <newren@gmail.com> wrote:\n> > > I'm not the unpack-trees man (I think that would still be Junio). And\n> > > I'm not saying it's sane either. I think it's just some leftover\n> > > things since Linus split \"the index\" in unpack-tree operation to\n> > > 'src', 'result' and 'dst' many years ago and nobody was brave enough\n> > > to clean it up (then I piled on with untracked cache and split index,\n> > > but I did not see it clearly either). That person could be you ;-)\n> >\n> > Hmm, might make a good New Year's resolution: Enter the abyss, find\n> > out if one can return from it...  or maybe I could just sanely run\n> > away screaming.  We'll see.\n>\n> I'm getting off topic. But my new years resolution would be optimize\n> for the case where src_index == dst_index, which is somewhat ironic\n> because we used to do everything in the same index, but it was a messy\n> mess and had to be split up.\n\nOoh, that sounds cool too.  I look forward to seeing it.\n"},{"id":"364975","messageId":"CABPp-BG9vjXF-entmun4+dMoOsZdjMgotSOtUUeNxO8c2VwgXA@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-8-t.gummerer@gmail.com","subject":"Re: [PATCH 7/8] checkout: allow ignoring unmatched pathspec","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T20:25:28Z","receivedAt":"2018-12-10T20:25:42Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Dec 9, 2018 at 12:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Currently when 'git checkout -- <pathspec>...' is invoked with\n> multiple pathspecs, where one or more of the pathspecs don't match\n> anything, checkout errors out.\n>\n> This can be inconvenient in some cases, such as when using git\n> checkout from a script.  Introduce a new --ignore-unmatched option,\n> which which allows us to ignore a non-matching pathspec instead of\n> erroring out.\n>\n> In a subsequent commit we're going to start using 'git checkout' in\n> 'git stash' and are going to make use of this feature.\n\nThis makes sense, but seems incomplete.  But to explain it, I think\nthere's another bug I need to demonstrate first because it's related\non builds on it.  First, the setup:\n\n  $ echo foo >subdir/newfile\n  $ git add subdir/newfile\n  $ echo bar >>subdir/newfile\n  $ git status\n  On branch A\n  Changes to be committed:\n    (use \"git reset HEAD <file>...\" to unstage)\n\n      new file:   subdir/newfile\n\n  Changes not staged for commit:\n    (use \"git add <file>...\" to update what will be committed)\n    (use \"git checkout -- <file>...\" to discard changes in working directory)\n\n      modified:   subdir/newfile\n\nNow, does it do what we expect?\n\n  $ git checkout HEAD -- subdir/newfile\n  error: pathspec 'subdir/newfile' did not match any file(s) known to git\n\nThis is the old overlay behavior; kinda lame, but you made no claims\nabout fixing the default behavior.  What about with your new option?\n\n  $ git checkout --no-overlay HEAD -- subdir\n  $ git status\n  On branch A\n  nothing to commit, working tree clean\n\nYes, the feature seems to work as advertised.  However, let's try\nagain with a different variant:\n\n  $ echo foo >subdir/newfile\n  $ git checkout --no-overlay HEAD -- subdir\n  $ git status\n  On branch A\n  Untracked files:\n    (use \"git add <file>...\" to include in what will be committed)\n\n      subdir/newfile\n\nWhy is the file ignored and left there?  Also:\n\n  $ git checkout --no-overlay HEAD -- subdir/newfile\n  error: pathspec 'subdir/newfile' did not match any file(s) known to git\n\nThat seems wrong to me.  The point of no-overlay is to make it match\nHEAD, and while subdir/newfile doesn't exist in HEAD or the index it\ndoes match in the working tree so the intent is clear. But let's say\nthat the user did go ahead and specify your new flag:\n\n\n  $ git checkout --no-overlay --ignore-unmatch HEAD -- subdir/newfile\n  $ git status\n  On branch A\n  Untracked files:\n    (use \"git add <file>...\" to include in what will be committed)\n\n      subdir/newfile\n\n  nothing added to commit but untracked files present (use \"git add\" to track)\n\nSo now it avoids erroring out when the user does more work than\nnecessary, but it still misses appropriately cleaning up the file.\n"},{"id":"364976","messageId":"CABPp-BHHC2ADhW5iPhAocCv7a-F+6T5vGboYa8kyHhLsBRCn-A@mail.gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-9-t.gummerer@gmail.com","subject":"Re: [PATCH 8/8] stash: use git checkout --no-overlay","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-10T20:26:38Z","receivedAt":"2018-12-10T20:26:54Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Dec 9, 2018 at 12:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n>\n> Now that we have 'git checkout --no-overlay', we can use it in git\n> stash, making the codepaths for 'git stash push' with and without\n> pathspec more similar, and thus easier to follow.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>\n> As mentioned in the cover letter, not sure if we want to apply this\n> now.  There are two reasons I did this:\n> - Showing the new functionality of git checkout\n> - Increased test coverage, as we are running the new code with all git\n>   stash tests for free, which helped look at some cases that I was\n>   missing initially.\n>\n>  git-stash.sh | 12 ++++--------\n>  1 file changed, 4 insertions(+), 8 deletions(-)\n>\n> diff --git a/git-stash.sh b/git-stash.sh\n> index 94793c1a91..67be04d996 100755\n> --- a/git-stash.sh\n> +++ b/git-stash.sh\n> @@ -314,19 +314,15 @@ push_stash () {\n>\n>         if test -z \"$patch_mode\"\n>         then\n> -               test \"$untracked\" = \"all\" && CLEAN_X_OPTION=-x || CLEAN_X_OPTION=\n> -               if test -n \"$untracked\" && test $# = 0\n> +               test \"$untracked\" = \"all\" && CLEAN_X_OPTION=-X || CLEAN_X_OPTION=\n> +               if test -n \"$untracked\"\n>                 then\n> -                       git clean --force --quiet -d $CLEAN_X_OPTION\n> +                       git clean --force --quiet -d $CLEAN_X_OPTION -- \"$@\"\n>                 fi\n>\n>                 if test $# != 0\n>                 then\n> -                       test -z \"$untracked\" && UPDATE_OPTION=\"-u\" || UPDATE_OPTION=\n> -                       test \"$untracked\" = \"all\" && FORCE_OPTION=\"--force\" || FORCE_OPTION=\n> -                       git add $UPDATE_OPTION $FORCE_OPTION -- \"$@\"\n> -                       git diff-index -p --cached --binary HEAD -- \"$@\" |\n> -                       git apply --index -R\n> +                       git checkout --quiet --no-overlay --ignore-unmatched HEAD -- \"$@\"\n\nNice.  :-)\n"},{"id":"365012","messageId":"xmqqftv4n6md.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CACsJy8AGerhjnT0O6vT264tND78N5cbgFREzYtdmriXERu0Jtw@mail.gmail.com","subject":"Re: [PATCH 2/8] entry: factor out unlink_entry function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-11T02:23:54Z","receivedAt":"2018-12-11T02:23:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> I wonder if we should move the 'removal' variable in symlinks to\n> 'struct checkout' to reduce another global variable. But I guess\n> that's the problem for another day. It's not the focus of this series.\n\nBefore any such move, I think it is important to notice that the\nthing is not thread friendly and devise a way to deal with it.\n"},{"id":"365014","messageId":"xmqqbm5sn6f6.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CACsJy8DQd_DcuogF2Wnj47F6ef26L1dea7M2Yi-ESZ_naQZ=kw@mail.gmail.com","subject":"Re: [PATCH 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-11T02:28:13Z","receivedAt":"2018-12-11T02:28:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n>> +       if (ce->ce_flags & CE_WT_REMOVE) {\n>> +               if (topath)\n>> +                       BUG(\"Can't remove entry to a path\");\n>> +               unlink_entry(ce);\n>> +               return 0;\n>> +       }\n>\n> This makes the path counting in nd/checkout-noisy less accurate. But\n> it's not your fault of course.\n\nWhen we check out absense of one path, how do we want to count it?\nDo we say \"one path checked out?\" when we remove one path?\n\n> Junio, do you still want to merge that series down to 'next' or drop\n> it? If it will be merged down, I'll keep a note and fix it once this\n> one lands too.\n\nSure, I still agree with you that \"git checkout\" that reports what\nit did when given a \"<branch>\", but does not report what it did when\ngiven a \"<pathspec>\", is being inconsistent.  If it makes it easier\nto manage, I can kick nd/checkout-noisy out of 'next' to be rebased\non whatever more appropriate when rewinding its tip.\n\nThanks.\n\n"},{"id":"365017","messageId":"xmqq7eggn5rk.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CACsJy8AiQvu8W4=2HLKMdg+n2HiDrcLvKPRurKvziXaJdqefRg@mail.gmail.com","subject":"Re: [PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-11T02:42:23Z","receivedAt":"2018-12-11T02:42:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> I'm still a bit scared of this invalidation business in unpack-trees.\n\nI too was (and I suspect that I would realize that I still am, if I\ntake another fresh look at the current code) afraid when I did the\ncache-tree work and decided to invalidate it as a whole upfront.\n\n> The thing is, we handle two separate index_state there, src_index and\n> result and invalidation has to be done on the right one (because index\n> extensions are on src_index until the very end of unpack-trees;\n> invalidating on 'result' would be no-op and wrong).\n> ...\n> Yeah I think it's because cache-tree and untracked cache are already\n> properly invalidated. ...\n\n"},{"id":"365018","messageId":"xmqqzhtclq22.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CABPp-BEk+7n2wcbjETishqnMBs5DGrTEvD7gahLtEj5bZ2AYvA@mail.gmail.com","subject":"Re: [PATCH 5/8] checkout: introduce --{,no-}overlay option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-11T03:07:01Z","receivedAt":"2018-12-11T03:07:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n>> Note that 'git checkout -p <tree-ish> -- [<pathspec>]' already works\n>> this way, so no changes are needed for the patch mode.  We disallow\n>> 'git checkout --overlay -p' to avoid confusing users who would expect\n>> to be able to force overlay mode in 'git checkout -p' this way.\n>\n> Whoa...that's interesting.  To me, that argues even further that the\n> traditional checkout behavior was wrong all along and the choice of\n> --overlay vs. --no-overlay in the original implementation was a total\n> oversight.  I'm really tempted to say that --no-overlay should just be\n> the default in checkout too...but maybe that's too high a hill to\n> climb, at least for now.\n\nYou are exhibiting a typical reaction to a shiny new toy.\n\nThe original \"checkout paths out of the trees and/or the index to\nrecover what was lost\" is modeled after \"cp -R .../else/where .\",\nwhich is an overlay operation, and you wouldn't imagine complaining\nthat \"cp -R\" is wrong not to remove things in the target, to be\nequivalent to \"rm -fr where && cp -R .../else/where .\".\n\nEach has its own uses.  We just didn't have the other half of the\npair.\n\nIf anything, I would consider \"checkout -p\" that does not do overlay\nis a bug that needs to be fixed.\n\n"},{"id":"365019","messageId":"xmqqva40lps2.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CACsJy8CfgJ4NAnbMjBFGhRWscZxJCgxtx0QwSMw7MTjeMT4gDw@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-11T03:13:01Z","receivedAt":"2018-12-11T03:13:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> Elijah wanted another mode (and I agree) that modifies worktree but\n> leaves the index alone. This is most useful (or least confusing) when\n> used with <tree-ish> and would be default in restore-files. I'm not\n> saying you have to implement it, but how do the new command line\n> options are designed to make sense?\n\nI'd model it after \"git apply\", i.e.\n\n\tgit restore-files [--tree=<treeish>] <pathspec>\n\nwould work only on the working tree files,\n\n\tgit restore-files --tree=<treeish> --cached <pathspec>\n\nwould match the entries in the index that match pathspec to the\ngiven treeish without touching the working tree, and\n\n\tgit restore-files --tree=<treeish> --index <pathspec>\n\nwould be both.\n\nI have never been happy with the phraso, the (arbitrary) distinction\nbetween --cached/--index we use, so in the very longer term (like,\nintroducing synonym at 3.0 boundary and deprecating older ones at\n4.0 boundary), it may not be a bad idea to rename \"--index\" to\n\"--index-and-working-tree\" and \"--cached\" to \"--index-only\".  \n\nBut until that happens, it would be better to use these two\nconsistently.\n"},{"id":"365038","messageId":"CABPp-BG-n6vw7qQ=PQgnyAqmSechbz6eaSduNxuA6_Mdp4D-ew@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqzhtclq22.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 5/8] checkout: introduce --{,no-}overlay option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-11T06:04:31Z","receivedAt":"2018-12-11T06:04:48Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Dec 10, 2018 at 7:07 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> >> Note that 'git checkout -p <tree-ish> -- [<pathspec>]' already works\n> >> this way, so no changes are needed for the patch mode.  We disallow\n> >> 'git checkout --overlay -p' to avoid confusing users who would expect\n> >> to be able to force overlay mode in 'git checkout -p' this way.\n> >\n> > Whoa...that's interesting.  To me, that argues even further that the\n> > traditional checkout behavior was wrong all along and the choice of\n> > --overlay vs. --no-overlay in the original implementation was a total\n> > oversight.  I'm really tempted to say that --no-overlay should just be\n> > the default in checkout too...but maybe that's too high a hill to\n> > climb, at least for now.\n>\n> You are exhibiting a typical reaction to a shiny new toy.\n>\n> The original \"checkout paths out of the trees and/or the index to\n> recover what was lost\" is modeled after \"cp -R .../else/where .\",\n> which is an overlay operation, and you wouldn't imagine complaining\n> that \"cp -R\" is wrong not to remove things in the target, to be\n> equivalent to \"rm -fr where && cp -R .../else/where .\".\n>\n> Each has its own uses.  We just didn't have the other half of the\n> pair.\n\nAh, modelled on cp -R.  I think that rather than reacting \"to a shiny\nnew toy\", I just had always had a different mental model AND failed to\nfigure out what the original model was, leading me to always view it\nas buggy.  Thanks for giving me the model I was missing.\n\n> If anything, I would consider \"checkout -p\" that does not do overlay\n> is a bug that needs to be fixed.\n\nYeah, --no-overlay being the default for -p, and --overlay being the\ndefault otherwise is rather inconsistent.  (Though I'm also fine with\nthat being fixed by some future patch series.)\n"},{"id":"365040","messageId":"CABPp-BGQwtok1T3WmY3ndBG6RjbESSOgmbZxkWiN-avqfUjDVg@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqva40lps2.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-12-11T06:12:09Z","receivedAt":"2018-12-11T06:12:24Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, Dec 10, 2018 at 7:13 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n> > Elijah wanted another mode (and I agree) that modifies worktree but\n> > leaves the index alone. This is most useful (or least confusing) when\n> > used with <tree-ish> and would be default in restore-files. I'm not\n> > saying you have to implement it, but how do the new command line\n> > options are designed to make sense?\n>\n> I'd model it after \"git apply\", i.e.\n>\n>         git restore-files [--tree=<treeish>] <pathspec>\n>\n> would work only on the working tree files,\n>\n>         git restore-files --tree=<treeish> --cached <pathspec>\n>\n> would match the entries in the index that match pathspec to the\n> given treeish without touching the working tree, and\n>\n>         git restore-files --tree=<treeish> --index <pathspec>\n>\n> would be both.\n>\n> I have never been happy with the phraso, the (arbitrary) distinction\n> between --cached/--index we use, so in the very longer term (like,\n> introducing synonym at 3.0 boundary and deprecating older ones at\n> 4.0 boundary), it may not be a bad idea to rename \"--index\" to\n> \"--index-and-working-tree\" and \"--cached\" to \"--index-only\".\n>\n> But until that happens, it would be better to use these two\n> consistently.\n\nI agree that consistency is important, but trying to distinguish\nbetween \"--cached\" and \"--index\" is _extremely_ painful.  I still\ncan't keep the distinction straight and have to look it up every time\nI want to use either.  I don't know how to possibly teach users the\nmeaning.  Could we introduce synonyms earlier at least, and make the\nsynonyms more prominent than the \"--cached\" and \"--index\" terms in the\ndocumentation?\n"},{"id":"365112","messageId":"CACsJy8AxUxYCO7bzb98EVvO5DU62ukZQNrF-sEktrdR9m6tfvg@mail.gmail.com","threadId":"49988","inReplyTo":"CABPp-BGQwtok1T3WmY3ndBG6RjbESSOgmbZxkWiN-avqfUjDVg@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-11T19:23:33Z","receivedAt":"2018-12-11T19:24:02Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Dec 11, 2018 at 7:12 AM Elijah Newren <newren@gmail.com> wrote:\n>\n> On Mon, Dec 10, 2018 at 7:13 PM Junio C Hamano <gitster@pobox.com> wrote:\n> >\n> > Duy Nguyen <pclouds@gmail.com> writes:\n> >\n> > > Elijah wanted another mode (and I agree) that modifies worktree but\n> > > leaves the index alone. This is most useful (or least confusing) when\n> > > used with <tree-ish> and would be default in restore-files. I'm not\n> > > saying you have to implement it, but how do the new command line\n> > > options are designed to make sense?\n> >\n> > I'd model it after \"git apply\", i.e.\n> >\n> >         git restore-files [--tree=<treeish>] <pathspec>\n> >\n> > would work only on the working tree files,\n> >\n> >         git restore-files --tree=<treeish> --cached <pathspec>\n> >\n> > would match the entries in the index that match pathspec to the\n> > given treeish without touching the working tree, and\n> >\n> >         git restore-files --tree=<treeish> --index <pathspec>\n> >\n> > would be both.\n> >\n> > I have never been happy with the phraso, the (arbitrary) distinction\n> > between --cached/--index we use, so in the very longer term (like,\n> > introducing synonym at 3.0 boundary and deprecating older ones at\n> > 4.0 boundary), it may not be a bad idea to rename \"--index\" to\n> > \"--index-and-working-tree\" and \"--cached\" to \"--index-only\".\n> >\n> > But until that happens, it would be better to use these two\n> > consistently.\n>\n> I agree that consistency is important, but trying to distinguish\n> between \"--cached\" and \"--index\" is _extremely_ painful.  I still\n> can't keep the distinction straight and have to look it up every time\n> I want to use either.  I don't know how to possibly teach users the\n> meaning.  Could we introduce synonyms earlier at least, and make the\n> synonyms more prominent than the \"--cached\" and \"--index\" terms in the\n> documentation?\n\nFor git-checkout I think --index and --cached fit. For restore-files,\nif you come up with better names, I'll gladly use that. Otherwise I'll\njust use these.\n-- \nDuy\n"},{"id":"365124","messageId":"20181211215019.GO4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CACsJy8AgbU9YyMHXdp=bkMncBO_Mu0FOQ4kSRkgacHzTJ0DrdA@mail.gmail.com","subject":"Re: [PATCH 1/8] move worktree tests to t24*","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T21:50:19Z","receivedAt":"2018-12-11T21:50:24Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Duy Nguyen wrote:\n> On Sun, Dec 9, 2018 at 9:04 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > The 'git worktree' command used to be just another mode in 'git\n> > checkout', namely 'git checkout --to'.  When the tests for the latter\n> > were retrofitted for the former, the test name was adjusted, but the\n> > test number was kept, even though the test is testing a different\n> > command now.  t/README states: \"Second digit tells the particular\n> > command we are testing.\", so 'git worktree' should have a separate\n> > number just for itself.\n> >\n> > Move the worktree tests to t24* to adhere to that guideline. We're\n> > going to make use of the free'd up numbers in a subsequent commit.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >  t/{t2025-worktree-add.sh => t2400-worktree-add.sh}     | 0\n> >  t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} | 0\n> >  t/{t2027-worktree-list.sh => t2402-worktree-list.sh}   | 0\n> >  3 files changed, 0 insertions(+), 0 deletions(-)\n> >  rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n> >  rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n> >  rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n> \n> Heh.. I did the same thing (in my unsent switch-branch/restore-files\n> series) and even used the same 24xx range :D You probably want to move\n> t2028 and t2029 too (not sure if they have landed on 'master')\n\n:)  I unfortunately didn't have time to read the\nswitch-branch/restore-files series in detail, but good to know someone\nthought the same way.  I started this work before t2028 and t2029\nlanded on master, so I failed to notice them.  But I'll rebase on\nmaster and move these two tests as well, thanks for noticing.\n\n> -- \n> Duy\n"},{"id":"365125","messageId":"20181211215910.GP4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CABPp-BEkeRa7jOkDcNNpZMY9J9JmNGtMKjZeNv8i_u7jUFihcw@mail.gmail.com","subject":"Re: [PATCH 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T21:59:10Z","receivedAt":"2018-12-11T21:59:15Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Elijah Newren wrote:\n> On Mon, Dec 10, 2018 at 8:09 AM Duy Nguyen <pclouds@gmail.com> wrote:\n> >\n> > On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > >\n> > > When marking cache entries for removal, and later removing them all at\n> > > once using 'remove_marked_cache_entries()', cache entries currently\n> > > have to be invalidated manually in the cache tree and in the untracked\n> > > cache.\n> > >\n> > > Add an invalidate flag to the function.  With the flag set, the\n> > > function will take care of invalidating the path in the cache tree and\n> > > in the untracked cache.\n> > >\n> > > This will be useful in a subsequent commit.\n> > >\n> > > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > > ---\n> > >\n> > > For the two current callsites, unpack-trees seems to do this\n> > > invalidation itself internally.\n> >\n> > I'm still a bit scared of this invalidation business in unpack-trees.\n> > The thing is, we handle two separate index_state there, src_index and\n> > result and invalidation has to be done on the right one (because index\n> > extensions are on src_index until the very end of unpack-trees;\n> > invalidating on 'result' would be no-op and wrong).\n> > remove_marked_cache_entries() seems to be called on 'result' while\n> > invalidate_ce_path() is on src_index, hm....\n> \n> Is Thomas avoiding problems here simply because merge is the only\n> caller of unpack_trees with src_index != dst_index?  Or does src_index\n> == dst_index for checkout not actually help?\n\nI'm trying to avoid problems in this patch by keeping status quo, and\nnot changing the cache-tree invalidation in any way.  'git checkout --\n<pathspec>' doesn't use unpack-trees, so I don't think I have to worry\nabout src_index vs. dst_index.\n\nIn what I was saying above I was merely trying to explain why we don't\nneed invalidate the cache-tree in the 'remove_marked_cache_entries()'\nfunction.\n\n> If that does help with the checkout case, then allow me to find a\n> different way to muddy the waters...  I think I might want to make use\n> of this function in the merge machinery at some point, so I either\n> need to figure out how to convince you to verify if all this cache\n> tree invalidation stuff is sane, or somehow figure out all the\n> cache_tree stuff stuff myself so I can figure out what is right here.\n> :-)\n> \n> > > I don't quite understand why we don't\n> > > need it in split-index mode though.  I assume it's because the cache\n> > > tree in the main index would already have been invalidated?  I didn't\n> > > have much time to dig, but couldn't produce any failures with it\n> > > either, so I assume not invalidating paths is the right thing to do\n> > > here.\n> >\n> > Yeah I think it's because cache-tree and untracked cache are already\n> > properly invalidated. This merge base thingy is done when we load the\n> > index files up, not when we write them down. The \"front\" index may\n> > record that a few paths in the base index are no longer valid and need\n> > to be deleted. But untracked cache and cache-tree both should have\n> > recorded that same info when these paths are marked for delete at\n> > index write time.\n\nThanks, that makes sense to me.\n"},{"id":"365126","messageId":"20181211220021.GQ4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CABPp-BHO7UmAm14HWf2tc+SVEZuWBqyvvrQg625fDsiDYPEL8g@mail.gmail.com","subject":"Re: [PATCH 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T22:00:22Z","receivedAt":"2018-12-11T22:00:29Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Elijah Newren wrote:\n> On Sun, Dec 9, 2018 at 12:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > 'checkout_entry()' currently only supports creating new entries in the\n> > working tree, but not deleting them.  Add the ability to remove\n> > entries at the same time if the entry is marked with the CE_WT_REMOVE\n> > flag.\n> >\n> > Currently this doesn't have any effect, as the CE_WT_REMOVE flag is\n> > only used in unpack-tree, however we will make use of this in a\n> > subsequent step in the series.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >  entry.c | 7 +++++++\n> >  1 file changed, 7 insertions(+)\n> >\n> > diff --git a/entry.c b/entry.c\n> > index 3ec148ceee..cd1c6601b6 100644\n> > --- a/entry.c\n> > +++ b/entry.c\n> > @@ -441,6 +441,13 @@ int checkout_entry(struct cache_entry *ce,\n> >         static struct strbuf path = STRBUF_INIT;\n> >         struct stat st;\n> >\n> > +       if (ce->ce_flags & CE_WT_REMOVE) {\n> > +               if (topath)\n> > +                       BUG(\"Can't remove entry to a path\");\n> \n> Minor nit: This error message is kinda hard to parse, for someone not\n> that familiar with all the *_entry functions, like myself.  Maybe add\n> a comment before this line:\n>     /* No content and thus no path to create, so we have no pathname\n> to return */\n> or reword the error slightly?  Or maybe it's fine and I was just\n> confused from lack of code familiarity, but I'll throw it out there\n> since I stumbled on it a bit.\n\nI'll try to make it more clear in the new round, thanks!\n\n> > +               unlink_entry(ce);\n> > +               return 0;\n> > +       }\n> > +\n> >         if (topath)\n> >                 return write_entry(ce, topath, state, 1);\n> >\n> > --\n> > 2.20.0.405.gbc1bbc6f85\n"},{"id":"365127","messageId":"20181211220752.GR4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"xmqqzhtclq22.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 5/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T22:07:52Z","receivedAt":"2018-12-11T22:07:57Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/11, Junio C Hamano wrote:\n> Elijah Newren <newren@gmail.com> writes:\n> \n> >> Note that 'git checkout -p <tree-ish> -- [<pathspec>]' already works\n> >> this way, so no changes are needed for the patch mode.  We disallow\n> >> 'git checkout --overlay -p' to avoid confusing users who would expect\n> >> to be able to force overlay mode in 'git checkout -p' this way.\n> >\n> > Whoa...that's interesting.  To me, that argues even further that the\n> > traditional checkout behavior was wrong all along and the choice of\n> > --overlay vs. --no-overlay in the original implementation was a total\n> > oversight.  I'm really tempted to say that --no-overlay should just be\n> > the default in checkout too...but maybe that's too high a hill to\n> > climb, at least for now.\n> \n> You are exhibiting a typical reaction to a shiny new toy.\n\nI wonder whether it's worth introducing a config option for this, so\npeople could use this new mode by default if they wanted to, without\nhaving to type the extra argument?\n\n'git checkout' is a plumbing command, but I see that some of the shell\nscripts in git.git are using it.  Though they are only using it in the\ncheckout branch mode, rather than the checkout paths mode.\n\n> The original \"checkout paths out of the trees and/or the index to\n> recover what was lost\" is modeled after \"cp -R .../else/where .\",\n> which is an overlay operation, and you wouldn't imagine complaining\n> that \"cp -R\" is wrong not to remove things in the target, to be\n> equivalent to \"rm -fr where && cp -R .../else/where .\".\n> \n> Each has its own uses.  We just didn't have the other half of the\n> pair.\n> \n> If anything, I would consider \"checkout -p\" that does not do overlay\n> is a bug that needs to be fixed.\n> \n"},{"id":"365128","messageId":"20181211221825.GS4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CABPp-BEyRNniNFBuMMFXjvuSz9RtP6R7TeBAWDJO+Y70oe7CBA@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T22:18:25Z","receivedAt":"2018-12-11T22:18:31Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Elijah Newren wrote:\n> On Sun, Dec 9, 2018 at 12:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > Add a new --cached option to git checkout, which works only on the\n> > index, but not the working tree, similar to what 'git reset <tree-ish>\n> > -- <pathspec>... does.  Indeed the tests are adapted from the 'git\n> > reset' tests.\n> >\n> > In the longer term the idea is to potentially deprecate 'git reset\n> > <tree-ish> -- <pathspec>...', so the 'git reset' command becomes only\n> > about re-pointing the HEAD, and not also about copying entries from\n> > <tree-ish> to the index.\n> >\n> > Note that 'git checkout' by default works in overlay mode, meaning\n> > files that match the pathspec that don't exist in <tree-ish>, but\n> > exist in the index would not be removed.  'git checkout --no-overlay\n> > --cached' can be used to get the same behaviour as 'git reset\n> > <tree-ish> -- <pathspec>'.\n> \n> I think this argues _even more_ that --no-overlay should be the\n> default.  Your series is valuable even if we don't push on that, I'm\n> just being noisy about what I think would be an even better world.\n\nI think just having that mode in 'git restore-files' Duy is working on\nmay have to be enough for now.\n\n> Also, I don't think I've mentioned it yet, but I'm really excited\n> about this series and what you're doing.  It's super cool.  (Which I\n> expected when I saw the description of the desired behavior, but I'm\n> also liking and contemplating re-using some code...)\n\nThanks :)\n\n> > One thing this patch doesn't currently deal with is conflicts.\n> > Currently 'git checkout --{ours,theirs} -- <file-with-conflicts>'\n> > doesn't do anything with the index, so the --cached option just\n> > mirrors that behaviour.  But given it doesn't even deal with\n> > conflicts, the '--cached' option doesn't make much sense when no\n> > <tree-ish> is given.  As it operates only on the index, it's always a\n> > no-op if no tree-ish is given.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >\n> > Maybe we can just disallow --cached without <tree-ish> given for now,\n> > and possibly later allow it with some different behaviour for\n> > conflicts, not sure what the best way forward here is.  We can also\n> > just make it update the index as appropriate, and have it behave\n> > different than 'git checkout' curerntly does when handling conflicts?\n> \n> Huh?\n>   \"git checkout -- <path>\"\n> means update <path> from the index, meaning the index is left alone\n> (it's the source) and only the working tree is touched.\n> \n> When you add a flag named --cached to only update the index and not\n> the working tree, then the index becomes the sole destination.\n> \n> Now we combine: no tree is specified means the index is the source of\n> the writing, and --cached being specified means the index is the sole\n> destination of the writing.  Thus, you have a no-op.  If the user\n> specifies --cached and no tree, you should immediately exit with a\n> message along the lines of \"Nothing to do; no tree given and --cached\n> specified.\"  The presence of conflicts seems completely irrelevant to\n> me here.\n\nAh yeah you're right, thanks for a sanity check.  The command I was\nmost worried about was 'git checkout --cached --{ours,theirs} -- <pathspec>', \nwhich I thought should update the index.  But as we don't give any\ntree-ish, I'm not sure anymore it should.  Maybe just always exiting\nwith the message you mention above is the right thing to do.\n\n> >  builtin/checkout.c         |  26 ++++++++--\n> >  t/t2016-checkout-patch.sh  |   8 +++\n> >  t/t2026-checkout-cached.sh | 103 +++++++++++++++++++++++++++++++++++++\n> >  t/t9902-completion.sh      |   1 +\n> >  4 files changed, 135 insertions(+), 3 deletions(-)\n> >  create mode 100755 t/t2026-checkout-cached.sh\n> >\n> > diff --git a/builtin/checkout.c b/builtin/checkout.c\n> > index 0aef35bbc4..6ba85e9de5 100644\n> > --- a/builtin/checkout.c\n> > +++ b/builtin/checkout.c\n> > @@ -45,6 +45,7 @@ struct checkout_opts {\n> >         int ignore_other_worktrees;\n> >         int show_progress;\n> >         int overlay_mode;\n> > +       int cached;\n> >         /*\n> >          * If new checkout options are added, skip_merge_working_tree\n> >          * should be updated accordingly.\n> > @@ -288,6 +289,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n> >                 die(_(\"Cannot update paths and switch to branch '%s' at the same time.\"),\n> >                     opts->new_branch);\n> >\n> > +       if (opts->patch_mode && opts->cached)\n> > +               return run_add_interactive(revision, \"--patch=reset\",\n> > +                                          &opts->pathspec);\n> > +\n> >         if (opts->patch_mode)\n> >                 return run_add_interactive(revision, \"--patch=checkout\",\n> >                                            &opts->pathspec);\n> > @@ -319,7 +324,9 @@ static int checkout_paths(const struct checkout_opts *opts,\n> >                                  * the current index, which means that it should\n> >                                  * be removed.\n> >                                  */\n> > -                               ce->ce_flags |= CE_MATCHED | CE_REMOVE | CE_WT_REMOVE;\n> > +                               ce->ce_flags |= CE_MATCHED | CE_REMOVE;\n> > +                               if (!opts->cached)\n> > +                                       ce->ce_flags |= CE_WT_REMOVE;\n> >                                 continue;\n> >                         } else {\n> >                                 /*\n> > @@ -392,6 +399,9 @@ static int checkout_paths(const struct checkout_opts *opts,\n> >         for (pos = 0; pos < active_nr; pos++) {\n> >                 struct cache_entry *ce = active_cache[pos];\n> >                 if (ce->ce_flags & CE_MATCHED) {\n> > +                       if (opts->cached) {\n> > +                               continue;\n> > +                       }\n> >                         if (!ce_stage(ce)) {\n> >                                 errs |= checkout_entry(ce, &state, NULL);\n> >                                 continue;\n> > @@ -571,6 +581,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,\n> >          * not tested here\n> >          */\n> >\n> > +       /*\n> > +        * opts->cached cannot be used with switching branches so is\n> > +        * not tested here\n> > +        */\n> > +\n> >         /*\n> >          * If we aren't creating a new branch any changes or updates will\n> >          * happen in the existing branch.  Since that could only be updating\n> > @@ -1207,9 +1222,13 @@ static int checkout_branch(struct checkout_opts *opts,\n> >                 die(_(\"'%s' cannot be used with switching branches\"),\n> >                     \"--patch\");\n> >\n> > -       if (!opts->overlay_mode)\n> > +       if (opts->overlay_mode != -1)\n> > +               die(_(\"'%s' cannot be used with switching branches\"),\n> > +                   \"--overlay/--no-overlay\");\n> > +\n> > +       if (opts->cached)\n> >                 die(_(\"'%s' cannot be used with switching branches\"),\n> > -                   \"--no-overlay\");\n> > +                   \"--cached\");\n> >\n> >         if (opts->writeout_stage)\n> >                 die(_(\"'%s' cannot be used with switching branches\"),\n> > @@ -1300,6 +1319,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n> >                             PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n> >                 OPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n> >                 OPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n> > +               OPT_BOOL(0, \"cached\", &opts.cached, N_(\"work on the index only\")),\n> >                 OPT_END(),\n> >         };\n> >\n> > diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh\n> > index 47aeb0b167..e8774046e0 100755\n> > --- a/t/t2016-checkout-patch.sh\n> > +++ b/t/t2016-checkout-patch.sh\n> > @@ -108,6 +108,14 @@ test_expect_success PERL 'path limiting works: foo inside dir' '\n> >         verify_state dir/foo head head\n> >  '\n> >\n> > +test_expect_success PERL 'git checkout --cached -p' '\n> > +       set_and_save_state dir/foo work work &&\n> > +       test_write_lines n y | git checkout --cached -p >output &&\n> > +       verify_state dir/foo work head &&\n> > +       verify_saved_state bar &&\n> > +       test_i18ngrep \"Unstage\" output\n> > +'\n> > +\n> >  test_expect_success PERL 'none of this moved HEAD' '\n> >         verify_saved_head\n> >  '\n> > diff --git a/t/t2026-checkout-cached.sh b/t/t2026-checkout-cached.sh\n> > new file mode 100755\n> > index 0000000000..1b66192727\n> > --- /dev/null\n> > +++ b/t/t2026-checkout-cached.sh\n> > @@ -0,0 +1,103 @@\n> > +#!/bin/sh\n> > +\n> > +test_description='checkout --cached <pathspec>'\n> > +\n> > +. ./test-lib.sh\n> > +\n> > +test_expect_success 'checkout --cached <pathspec>' '\n> > +       echo 1 >file1 &&\n> > +       echo 2 >file2 &&\n> > +       git add file1 file2 &&\n> > +       test_tick &&\n> > +       git commit -m files &&\n> > +       git rm file2 &&\n> > +       echo 3 >file3 &&\n> > +       echo 4 >file1 &&\n> > +       git add file1 file3 &&\n> > +       git checkout --cached HEAD -- file1 file2 &&\n> > +       test_must_fail git diff --quiet &&\n> > +\n> > +       cat >expect <<-\\EOF &&\n> > +       diff --git a/file1 b/file1\n> > +       index d00491f..b8626c4 100644\n> > +       --- a/file1\n> > +       +++ b/file1\n> > +       @@ -1 +1 @@\n> > +       -1\n> > +       +4\n> > +       diff --git a/file2 b/file2\n> > +       deleted file mode 100644\n> > +       index 0cfbf08..0000000\n> > +       --- a/file2\n> > +       +++ /dev/null\n> > +       @@ -1 +0,0 @@\n> > +       -2\n> > +       EOF\n> > +       git diff >actual &&\n> > +       test_cmp expect actual &&\n> > +\n> > +       cat >expect <<-\\EOF &&\n> > +       diff --git a/file3 b/file3\n> > +       new file mode 100644\n> > +       index 0000000..00750ed\n> > +       --- /dev/null\n> > +       +++ b/file3\n> > +       @@ -0,0 +1 @@\n> > +       +3\n> > +       EOF\n> > +       git diff --cached >actual &&\n> > +       test_cmp expect actual\n> > +'\n> > +\n> > +test_expect_success 'checking out an unmodified path is a no-op' '\n> > +       git reset --hard &&\n> > +       git checkout --cached HEAD -- file1 &&\n> > +       git diff-files --exit-code &&\n> > +       git diff-index --cached --exit-code HEAD\n> > +'\n> > +\n> > +test_expect_success 'checking out specific path that is unmerged' '\n> > +       test_commit file3 file3 &&\n> > +       git rm --cached file2 &&\n> > +       echo 1234 >file2 &&\n> > +       F1=$(git rev-parse HEAD:file1) &&\n> > +       F2=$(git rev-parse HEAD:file2) &&\n> > +       F3=$(git rev-parse HEAD:file3) &&\n> > +       {\n> > +               echo \"100644 $F1 1      file2\" &&\n> > +               echo \"100644 $F2 2      file2\" &&\n> > +               echo \"100644 $F3 3      file2\"\n> > +       } | git update-index --index-info &&\n> > +       git ls-files -u &&\n> > +       git checkout --cached HEAD file2 &&\n> > +       test_must_fail git diff --quiet &&\n> > +       git diff-index --exit-code --cached HEAD\n> > +'\n> > +\n> > +test_expect_success '--cached without --no-overlay does not remove entry from index' '\n> > +       test_must_fail git checkout --cached HEAD^ file3 &&\n> > +       git ls-files --error-unmatch -- file3\n> > +'\n> > +\n> > +test_expect_success 'file is removed from the index with --no-overlay' '\n> > +       git checkout --cached --no-overlay HEAD^ file3 &&\n> > +       test_path_is_file file3 &&\n> > +       test_must_fail git ls-files --error-unmatch -- file3\n> > +'\n> > +\n> > +test_expect_success 'test checkout --cached --no-overlay at given paths' '\n> > +       mkdir sub &&\n> > +       >sub/file1 &&\n> > +       >sub/file2 &&\n> > +       git update-index --add sub/file1 sub/file2 &&\n> > +       T=$(git write-tree) &&\n> > +       git checkout --cached --no-overlay HEAD sub/file2 &&\n> > +       test_must_fail git diff --quiet &&\n> > +       U=$(git write-tree) &&\n> \n> Do we need to worry at all about losing the exit status of write-tree\n> in either invocation?  In particular, if the second one for U fails\n> somehow, we'd end up with $U being a blank string and we'd still\n> probably get \"$T\" != \"$U\" below.\n\nHmm this seems to be a fairly common pattern in our test suite:\n\n$ git grep -F '$(git write-tree)' t/* | wc -l\n112\n\nBut maybe it's just something we used to do, but should move away\nfrom.  Just writing the output to a file shouldn't be much harder\neither, I'll do that in the next iteration.\n\n> You also had some rev-parse invocations hidden in a sub-shell in both\n> this patch and patch 5, but subsequent commands relied on non-empty\n> output out of those, so I figured those were fine.  This one might be\n> too, but I thought I'd at least mention it.\n> \n> > +       echo \"$T\" &&\n> > +       echo \"$U\" &&\n> > +       test_must_fail git diff-index --cached --exit-code \"$T\" &&\n> > +       test \"$T\" != \"$U\"\n> > +'\n> > +\n> > +test_done\n> > diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\n> > index a3fd9a9630..cbc304ace8 100755\n> > --- a/t/t9902-completion.sh\n> > +++ b/t/t9902-completion.sh\n> > @@ -1437,6 +1437,7 @@ test_expect_success 'double dash \"git checkout\"' '\n> >         --no-quiet Z\n> >         --no-... Z\n> >         --overlay Z\n> > +       --cached Z\n> >         EOF\n> >  '\n> >\n> > --\n> > 2.20.0.405.gbc1bbc6f85\n"},{"id":"365129","messageId":"20181211222312.GT4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CACsJy8CjQHGANKf2Z=vJL=_ktoeXxOzQGL+VFJC4W63fzok78g@mail.gmail.com","subject":"Re: [PATCH 7/8] checkout: allow ignoring unmatched pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T22:23:12Z","receivedAt":"2018-12-11T22:23:19Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Duy Nguyen wrote:\n> On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > Currently when 'git checkout -- <pathspec>...' is invoked with\n> > multiple pathspecs, where one or more of the pathspecs don't match\n> > anything, checkout errors out.\n> >\n> > This can be inconvenient in some cases, such as when using git\n> > checkout from a script.\n> \n> Wait, should scripts go with read-tree, checkout-index or other\n> plumbing commands instead?\n\nPossibly.  As mentioned in an other email, we do seem to have some\nscripts in git.git that are using 'git checkout' already, but they are\nusing it in the checkout branch mode, rather than the checkout paths\nmode that I would like to use it in git-stash.\n\nBut with the rewrite of 'git stash' in C, maybe this step is moot\nanyway, and we can just call the checkout_paths function internally\nwithout using the run_command API at all.  We could then have an\ninternal mode for ignoring unmatched pathspecs that we wouldn't need\nto expose to users.\n\n> -- \n> Duy\n"},{"id":"365130","messageId":"20181211223642.GU4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CABPp-BG9vjXF-entmun4+dMoOsZdjMgotSOtUUeNxO8c2VwgXA@mail.gmail.com","subject":"Re: [PATCH 7/8] checkout: allow ignoring unmatched pathspec","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T22:36:42Z","receivedAt":"2018-12-11T22:36:48Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Elijah Newren wrote:\n> On Sun, Dec 9, 2018 at 12:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > Currently when 'git checkout -- <pathspec>...' is invoked with\n> > multiple pathspecs, where one or more of the pathspecs don't match\n> > anything, checkout errors out.\n> >\n> > This can be inconvenient in some cases, such as when using git\n> > checkout from a script.  Introduce a new --ignore-unmatched option,\n> > which which allows us to ignore a non-matching pathspec instead of\n> > erroring out.\n> >\n> > In a subsequent commit we're going to start using 'git checkout' in\n> > 'git stash' and are going to make use of this feature.\n> \n> This makes sense, but seems incomplete.  But to explain it, I think\n> there's another bug I need to demonstrate first because it's related\n> on builds on it.  First, the setup:\n> \n>   $ echo foo >subdir/newfile\n>   $ git add subdir/newfile\n>   $ echo bar >>subdir/newfile\n>   $ git status\n>   On branch A\n>   Changes to be committed:\n>     (use \"git reset HEAD <file>...\" to unstage)\n> \n>       new file:   subdir/newfile\n> \n>   Changes not staged for commit:\n>     (use \"git add <file>...\" to update what will be committed)\n>     (use \"git checkout -- <file>...\" to discard changes in working directory)\n> \n>       modified:   subdir/newfile\n> \n> Now, does it do what we expect?\n> \n>   $ git checkout HEAD -- subdir/newfile\n>   error: pathspec 'subdir/newfile' did not match any file(s) known to git\n> \n> This is the old overlay behavior; kinda lame, but you made no claims\n> about fixing the default behavior.  What about with your new option?\n> \n>   $ git checkout --no-overlay HEAD -- subdir\n>   $ git status\n>   On branch A\n>   nothing to commit, working tree clean\n> \n> Yes, the feature seems to work as advertised.  However, let's try\n> again with a different variant:\n> \n>   $ echo foo >subdir/newfile\n>   $ git checkout --no-overlay HEAD -- subdir\n>   $ git status\n>   On branch A\n>   Untracked files:\n>     (use \"git add <file>...\" to include in what will be committed)\n> \n>       subdir/newfile\n> \n> Why is the file ignored and left there?  Also:\n> \n>   $ git checkout --no-overlay HEAD -- subdir/newfile\n>   error: pathspec 'subdir/newfile' did not match any file(s) known to git\n> \n> That seems wrong to me.\n\nAh interesting, this is a case I didn't consider.  I'm a bit torn on\nthis one.  My intention for the no overlay mode was that it would work\nsimilar to what I'd expect 'git reset --hard -- <pathspec>' to work if\nit existed, which means not removing untracked files if they exist.\n\nWhile I think in the example you have above removing subdir/newfile\nmay be the right behaviour I'm not so sure in the case of 'git\ncheckout --no-overlay HEAD -- .' or ''git checkout --no-overlay HEAD\n-- t/*' for example.  I don't think that should remove all untracked\nfiles in the repository or in the t/ directory.  Removing untracked\nfiles in that case would probably surprise users more than your case\nabove would.\n\nI think it's okay to keep considering untracked files as special with\nrespect to how they are treated by 'git checkout --no-overlay'.\n\n>                          The point of no-overlay is to make it match\n> HEAD, and while subdir/newfile doesn't exist in HEAD or the index it\n> does match in the working tree so the intent is clear. But let's say\n> that the user did go ahead and specify your new flag:\n> \n> \n>   $ git checkout --no-overlay --ignore-unmatch HEAD -- subdir/newfile\n>   $ git status\n>   On branch A\n>   Untracked files:\n>     (use \"git add <file>...\" to include in what will be committed)\n> \n>       subdir/newfile\n> \n>   nothing added to commit but untracked files present (use \"git add\" to track)\n> \n> So now it avoids erroring out when the user does more work than\n> necessary, but it still misses appropriately cleaning up the file.\n\nYeah this is a good point, this could be more confusing to the user\nthan the previous case in my opinion.  Maybe I'll just drop this patch\nfor now (and the next one, as it's better to hold of until stash in C\nlands anyway), and then try to do all this in-core for 'git stash'.\n"},{"id":"365131","messageId":"20181211224239.GV4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CACsJy8BWZyFWZ70y4beCEYvjbc2+X-2K+gOiY+=toK0y3xYzKw@mail.gmail.com","subject":"Re: [PATCH 5/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T22:42:39Z","receivedAt":"2018-12-11T22:42:44Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Duy Nguyen wrote:\n> On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > @@ -302,15 +310,29 @@ static int checkout_paths(const struct checkout_opts *opts,\n> >                 ce->ce_flags &= ~CE_MATCHED;\n> >                 if (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n> >                         continue;\n> > -               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n> > -                       /*\n> > -                        * \"git checkout tree-ish -- path\", but this entry\n> > -                        * is in the original index; it will not be checked\n> > -                        * out to the working tree and it does not matter\n> > -                        * if pathspec matched this entry.  We will not do\n> > -                        * anything to this entry at all.\n> > -                        */\n> > -                       continue;\n> > +               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) {\n> > +                       if (!opts->overlay_mode &&\n> > +                           ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {\n> > +                               /*\n> > +                                * \"git checkout --no-overlay <tree-ish> -- path\",\n> > +                                * and the path is not in tree-ish, but is in\n> > +                                * the current index, which means that it should\n> > +                                * be removed.\n> > +                                */\n> > +                               ce->ce_flags |= CE_MATCHED | CE_REMOVE | CE_WT_REMOVE;\n> > +                               continue;\n> > +                       } else {\n> \n> In non-overlay mode but when pathspec does not match, we come here too.\n> \n> > +                               /*\n> > +                                * \"git checkout tree-ish -- path\", but this\n> > +                                * entry is in the original index; it will not\n> \n> I think the missing key point in this comment block is \"..is in the\n> original index _and it's not in tree-ish_\". In non-overlay mode, if\n> pathspec does not match then it's safe to ignore too. But this logic\n> starts too get to complex and hurt my brain.\n\nYes, that would make it a bit easier to read. I took a while to try\nand refactor this to make it easier to read, but couldn't come up with\nanything much better unfortunately.  I'll have another stab at\nsimplifying the logic a bit for v2.\n\n> > +                                * be checked out to the working tree and it\n> > +                                * does not matter if pathspec matched this\n> > +                                * entry.  We will not do anything to this entry\n> > +                                * at all.\n> > +                                */\n> > +                               continue;\n> > +                       }\n> > +               }\n> >                 /*\n> >                  * Either this entry came from the tree-ish we are\n> >                  * checking the paths out of, or we are checking out\n> \n> > @@ -1266,6 +1299,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n> >                             \"checkout\", \"control recursive updating of submodules\",\n> >                             PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n> >                 OPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n> > +               OPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n> \n> maybe add \" (default)\" to the help string.\n\nMakes sense, will add.\n\n> >                 OPT_END(),\n> >         };\n> >\n> -- \n> Duy\n"},{"id":"365132","messageId":"20181211225241.GW4883@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CABPp-BFaWtDiBPuGQVU_+VGQtDkemDKnvjHhz+h1sbUGssffmQ@mail.gmail.com","subject":"Re: [PATCH 0/8] introduce no-overlay and cached mode in git checkout","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-11T22:52:41Z","receivedAt":"2018-12-11T22:52:47Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Elijah Newren wrote:\n> On Sun, Dec 9, 2018 at 12:04 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > Here's the series I mentioned a couple of times on the list already,\n> > introducing a no-overlay mode in 'git checkout'.  The inspiration for\n> > this came from Junios message in [*1*].\n> >\n> > Basically the idea is to also delete files when the match <pathspec>\n> > in 'git checkout <tree-ish> -- <pathspec>' in the current tree, but\n> > don't match <pathspec> in <tree-ish>.  The rest of the cases are\n> > already properly taken care of by 'git checkout'.\n> \n> Yes, but I'd put it a little differently:\n> \n> \"\"\"\n> Basically, the idea is when the user run \"git checkout --no-overlay\n> <tree-ish> -- <pathspec>\" that the given pathspecs should exactly\n> match <tree-ish> after the operation completes.  This means that we\n> also want to delete files that match <pathspec> if those paths are not\n> found in <tree-ish>.\n> \"\"\"\n> \n> ...and maybe even toss in some comments about the fact that this is\n> the way git checkout should have always behaved, it just traditionally\n> hasn't.  (You could also work in comments about how with this new mode\n> the user can run git diff afterward with the given commit-ish and\n> pathspecs and get back an empty diff, as expected, which wasn't true\n> before.  But maybe I'm belaboring the point.)\n> \n> \n> > The final step in the series is to actually make use of this in 'git\n> > stash', which simplifies the code there a bit.  I am however happy to\n> > hold off on this step until the stash-in-C series is merged, so we\n> > don't delay that further.\n> >\n> > In addition to the no-overlay mode, we also add a --cached mode, which\n> > works only on the index, thus similar to 'git reset <tree-ish> -- <pathspec>'.\n> \n> If you're adding a --cached mode to make it only work on the index,\n> should there be a similar mode to allow it to only work on the working\n> tree?  (I'm not as concerned with that here, but I really think the\n> new restore-files command by default should only operate on the\n> working tree, and then have options to affect the index either in\n> addition or instead of the working tree.)\n\nYeah I think that would be nice to have, though I'm not sure what we\nwould name it in 'git checkout'.  Maybe just having it in 'git\nrestore-files' is good enough?\n\n> > Actually deprecating 'git reset <tree-ish> -- <pathspec>' should come\n> > later, probably not before Duy's restore-files command lands, as 'git\n> > checkout --no-overlay <tree-ish> -- <pathspec>' is a bit cumbersome to\n> > type compared to 'git reset <tree-ish> -- <pathspec>'.\n> \n> Makes sense.\n> \n> > My hope is also that the no-overlay mode could become the new default\n> > in the restore-files command Duy is currently working on.\n> \n> Absolutely, yes.  I don't want another broken command.  :-)\n> \n> \n> > No documentation yet, as I wanted to get this out for review first.\n> > I'm not familiar with most of the code I touched here, so there may\n> > well be much better ways to implement some of this, that I wasn't able\n> > to figure out.  I'd be very happy with some feedback around that.\n> >\n> > Another thing I'm not sure about is how to deal with conflicts.  In\n> > the cached mode this patch series is not dealing with it at all, as\n> > 'git checkout -- <pathspec>' when pathspec matches a file with\n> > conflicts doesn't update the index.  For the no-overlay mode, the file\n> > is removed if the corresponding stage is not found in the index.  I'm\n> > however not sure this is the right thing to do in all cases?\n> \n> Here's how I'd go about analyzing that...\n> \n> If the user passes a <tree-ish>, then the answer about what to do is\n> pretty obvious; the <tree-ish> didn't have conflicts, so conflicted\n> paths in the index that match the pathspec should be overwritten with\n> whatever version of those paths existed in <tree-ish> (possibly\n> implying deletion of some paths).\n> \n> Also, as you point out, --cached means only modify the index and not\n> the working tree; so if they specify both --cached and provide no\n> tree, then they've specified a no-op.\n> \n> So it's only interesting when you have conflicts in the index and\n> specify --no-overlay without a <tree-ish> or --cached.  This boils\n> down to \"how do we update the working tree to match the index, when\n> the index is conflicted?\"  A couple points to consider:\n>   * This is somewhat of an edge case\n>   * In the normal case --no-overlay is only different from --overlay\n> behavior for directories; it'd be nice if that extended to all cases\n\nI'm not sure I follow what you mean here.  How is --no-overlay\ndifferent from --overlay with respect to directories?  It's only\ndifferent with respect to deletions, no?\n\n>   * How does this command behave without a <tree-ish> when\n> --no-overlay is specified and a directory is given for a <pathspec>\n> and there aren't any conflicts?  Are we being consistent with that\n> behavior?\n> \n> \n> However, I think it turns out that the answer is much simpler than all\n> that initial analysis or what you say you've implemented.  Here's why:\n> \n> If <pathspec> is a file which is present in both the working tree and\n> the index and it has conflicts, then \"git checkout -- <pathspec>\" will\n> currently throw an error:\n\nI think what was missing from my original description, that actually\nmakes it slightly more interesting from what you describe below is the\n'--ours' and '--theirs' flags in 'git checkout', with which one can\ncheck out a version of the file in the working tree.  This is where it\ngets more interesting.\n\nI think I got the right solution for that in patch 5, with deleting\nthe file if it's deleted in \"their\" version and we pass --theirs to\n'git checkout', and analogous for --ours.  I was just wondering if\nthere were any further edge cases that I can't think of right no.\n\n> $ git checkout -- subdir/counting\n> error: path 'subdir/counting' is unmerged\n> \n> In fact, even if every entry in subdir/ is a path that is in both the\n> index and the working tree (so that --no-overlay and --overlay ought\n> to behave the same), if any one of the files in subdir is conflicted,\n> attempting to checkout the subdir will abort with this same error\n> message and no paths will be updated at all:\n> \n> $ git checkout -- subdir\n> error: path 'subdir/counting' is unmerged\n> \n> as such, the answer with what to do with --no-overlay mode is pretty\n> clear: if the <pathspec> matches _any_ path that is conflicted, simply\n> throw an error and abort the operation without making any changes at\n> all.\n"},{"id":"365152","messageId":"CACsJy8C6VuH=hr9JE+AXeqU5V9RwouzZSb5+jV++GHU3myoDTA@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqbm5sn6f6.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-12T06:16:02Z","receivedAt":"2018-12-12T06:16:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Dec 11, 2018 at 3:28 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n> >> +       if (ce->ce_flags & CE_WT_REMOVE) {\n> >> +               if (topath)\n> >> +                       BUG(\"Can't remove entry to a path\");\n> >> +               unlink_entry(ce);\n> >> +               return 0;\n> >> +       }\n> >\n> > This makes the path counting in nd/checkout-noisy less accurate. But\n> > it's not your fault of course.\n>\n> When we check out absense of one path, how do we want to count it?\n> Do we say \"one path checked out?\" when we remove one path?\n\nIt is still \"checked out\" according to this non-overlay concept.\nAlthough we could make it clear by saying \"5 paths updated, 2 deleted\"\n(but that may make us say \"3 paths added\" as well, hmm). Or maybe just\n\"%d paths updated\" where updates include file creation and deletion.\n-- \nDuy\n"},{"id":"365155","messageId":"xmqqk1kfjj9z.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"20181211225241.GW4883@hank.intra.tgummerer.com","subject":"Re: [PATCH 0/8] introduce no-overlay and cached mode in git checkout","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-12T07:28:40Z","receivedAt":"2018-12-12T07:28:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> I think I got the right solution for that in patch 5, with deleting\n> the file if it's deleted in \"their\" version and we pass --theirs to\n> 'git checkout', and analogous for --ours.  I was just wondering if\n> there were any further edge cases that I can't think of right no.\n\nThat sounds quite sensible.\n"},{"id":"365157","messageId":"xmqqftv3jiw8.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CACsJy8C6VuH=hr9JE+AXeqU5V9RwouzZSb5+jV++GHU3myoDTA@mail.gmail.com","subject":"Re: [PATCH 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-12-12T07:36:55Z","receivedAt":"2018-12-12T07:37:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> Although we could make it clear by saying \"5 paths updated, 2 deleted\"\n> (but that may make us say \"3 paths added\" as well, hmm). Or maybe just\n> \"%d paths updated\" where updates include file creation and deletion.\n\nYeah, the last one is the simplest and good.\n"},{"id":"365171","messageId":"CAPig+cQ0pPiB01KOWsC7a3mHdJz6LtAJjtf8=MWF+34NFdVb1g@mail.gmail.com","threadId":"49988","inReplyTo":"20181211215019.GO4883@hank.intra.tgummerer.com","subject":"Re: [PATCH 1/8] move worktree tests to t24*","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-12-12T13:26:58Z","receivedAt":"2018-12-12T13:27:13Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Dec 11, 2018 at 4:50 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> On 12/10, Duy Nguyen wrote:\n> > On Sun, Dec 9, 2018 at 9:04 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > > Move the worktree tests to t24* to adhere to that guideline. We're\n> > > going to make use of the free'd up numbers in a subsequent commit.\n> >\n> > Heh.. I did the same thing (in my unsent switch-branch/restore-files\n> > series) and even used the same 24xx range :D You probably want to move\n> > t2028 and t2029 too (not sure if they have landed on 'master')\n>\n> [...] good to know someone\n> thought the same way.  I started this work before t2028 and t2029\n> landed on master, so I failed to notice them.\n\nThe thought of renumbering the test script came up as early as\n2015-06-30. See the last bullet point of [1], for instance.\n\n[1]: https://public-inbox.org/git/1435640202-95945-1-git-send-email-sunshine@sunshineco.com/\n"},{"id":"365182","messageId":"CACsJy8Cr9V=UZAdRwUKXdCGO=Y=wPo4XViknij7uRAmAW1p2Hw@mail.gmail.com","threadId":"49988","inReplyTo":"CAPig+cQ0pPiB01KOWsC7a3mHdJz6LtAJjtf8=MWF+34NFdVb1g@mail.gmail.com","subject":"Re: [PATCH 1/8] move worktree tests to t24*","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-12T17:07:20Z","receivedAt":"2018-12-12T17:07:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 12, 2018 at 2:27 PM Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Tue, Dec 11, 2018 at 4:50 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > On 12/10, Duy Nguyen wrote:\n> > > On Sun, Dec 9, 2018 at 9:04 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > > > Move the worktree tests to t24* to adhere to that guideline. We're\n> > > > going to make use of the free'd up numbers in a subsequent commit.\n> > >\n> > > Heh.. I did the same thing (in my unsent switch-branch/restore-files\n> > > series) and even used the same 24xx range :D You probably want to move\n> > > t2028 and t2029 too (not sure if they have landed on 'master')\n> >\n> > [...] good to know someone\n> > thought the same way.  I started this work before t2028 and t2029\n> > landed on master, so I failed to notice them.\n>\n> The thought of renumbering the test script came up as early as\n> 2015-06-30. See the last bullet point of [1], for instance.\n>\n> [1]: https://public-inbox.org/git/1435640202-95945-1-git-send-email-sunshine@sunshineco.com/\n\nAh good. I thought I was just being lazy and picked a random range to add tests.\n-- \nDuy\n"},{"id":"365620","messageId":"20181220084351.GA8083@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"xmqqa7le2gc2.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 0/8] introduce no-overlay and cached mode in git checkout","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T08:43:51Z","receivedAt":"2018-12-20T08:43:57Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > Basically the idea is to also delete files when the match <pathspec>\n> > in 'git checkout <tree-ish> -- <pathspec>' in the current tree, but\n> > don't match <pathspec> in <tree-ish>.\n> \n> I cannot quite parse it, but perhaps.\n> \n> \t\"git checkout --no-overlay <tree-ish> -- <pathspec>\" can\n> \tremove paths in the index and in the working tree that match\n> \t<pathspec>, if they do not appear in <tree-ish>.\n> \n> If a new file D/F is in the index and in the working tree but not in\n> HEAD, \"git checkout HEAD D/\" or \"git checkout HEAD D/F\" would not\n> remove D/F from the index or the working tree.\n> \n> With the --no-overlay option, it would, and that is often closer to\n> the wish of the user who wanted to say \"restore the working tree\n> state of D/ (or D/F) from the state recorded in HEAD\".\n\nYeah thanks, that reads much better.\n\n> > The final step in the series is to actually make use of this in 'git\n> > stash', which simplifies the code there a bit.  I am however happy to\n> > hold off on this step until the stash-in-C series is merged, so we\n> > don't delay that further.\n> \n> I think that is probably a good idea, for now.\n> \n> > In addition to the no-overlay mode, we also add a --cached mode, which\n> > works only on the index, thus similar to 'git reset <tree-ish> -- <pathspec>'.\n> >\n> > Actually deprecating 'git reset <tree-ish> -- <pathspec>' should come\n> > later,...\n> \n> Or we may not even need to deprecate it.  IIRC, what \"stash\" wished\n> to exist was \"git reset --hard <tree-ish> -- <pathspec>\", which, if\n> the command followed \"--cached/--index\" convention, would have been\n> called \"git reset --index ...\".  Did we actually have the need for\n> \"--cached\" mode?\n\nI don't have a pressing need for \"--cached\".  I mainly included it\nbecause you described \"git reset <tree-ish> -- <pathspec>\" as bad UI\nin the original thread [*1*], which after reading that message I agree\nwith.  It also seemed to cause some confusion in [*2*].  Since it was\nfairly easy to introduce a \"--cached\" mode it seemed like a potential\nUI improvement in the long term to deprecate 'git reset <tree-ish> --\n<pathspec>'.\n\nThat said, this series is probably not the right place to introduce\nthis feature, as it should mainly be focused on the no-overlay mode.\nI'll drop the patch from v2.\n\nWe can revisit whether we want to introduce a \"--cached\" mode in 'git\ncheckout' at some point in the future.  \n\n> > probably not before Duy's restore-files command lands, as 'git\n> > checkout --no-overlay <tree-ish> -- <pathspec>' is a bit cumbersome to\n> > type compared to 'git reset <tree-ish> -- <pathspec>'.\n> \n> Yes, between \"checkout --cached\" and \"checkout --no-overlay\", the\n> latter is much more important, as the latter is what a missing \"git\n> reset --hard <tree-ish> -- <pathspec>\" would have been, but the\n> former can be written with an existing command.\n> \n> > My hope is also that the no-overlay mode could become the new default\n> > in the restore-files command Duy is currently working on.\n> \n> Yup, that is my hope, too ;-).\n\n*1*: <xmqq4loqplou.fsf@gitster.mtv.corp.google.com>\n*2*: <alpine.LFD.2.21.1812081103500.29142@localhost.localdomain>\n"},{"id":"365632","messageId":"20181220133643.GA25639@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CACsJy8AGerhjnT0O6vT264tND78N5cbgFREzYtdmriXERu0Jtw@mail.gmail.com","subject":"Re: [PATCH 2/8] entry: factor out unlink_entry function","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:36:43Z","receivedAt":"2018-12-20T13:36:49Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/10, Duy Nguyen wrote:\n> On Sun, Dec 9, 2018 at 9:05 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> >\n> > Factor out the 'unlink_entry()' function from unpack-trees.c to\n> > entry.c.  It will be used in other places as well in subsequent\n> > steps.\n> >\n> > As it's no longer a static function, also move the documentation to\n> > the header file to make it more discoverable.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >  cache.h        |  5 +++++\n> >  entry.c        | 15 +++++++++++++++\n> >  unpack-trees.c | 19 -------------------\n> >  3 files changed, 20 insertions(+), 19 deletions(-)\n> >\n> > diff --git a/cache.h b/cache.h\n> > index ca36b44ee0..c1c953e810 100644\n> > --- a/cache.h\n> > +++ b/cache.h\n> > @@ -1542,6 +1542,11 @@ struct checkout {\n> >  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);\n> >  extern void enable_delayed_checkout(struct checkout *state);\n> >  extern int finish_delayed_checkout(struct checkout *state);\n> > +/*\n> > + * Unlink the last component and schedule the leading directories for\n> > + * removal, such that empty directories get removed.\n> > + */\n> > +extern void unlink_entry(const struct cache_entry *ce);\n> \n> I'm torn. We try to remove 'extern' but I can see you may want to add\n> it here to be consistent with others. And removing extern even from\n> functions from entry.c only would cause some conflicts.\n\nYeah I felt like favoring consistency here would be better.  Once your\npath counting series and my series land, this may get quieter and we\ncan remove the 'extern' then?\n\n> I wonder if we should move the 'removal' variable in symlinks to\n> 'struct checkout' to reduce another global variable. But I guess\n> that's the problem for another day. It's not the focus of this\n> series.\n\nYeah, I'd prefer leaving that for another day :)\n\n> -- \n> Duy\n"},{"id":"365633","messageId":"20181220134820.21810-1-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181209200449.16342-1-t.gummerer@gmail.com","subject":"[PATCH v2 0/8] introduce no-overlay mode in git checkout","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:12Z","receivedAt":"2018-12-20T13:48:40Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Previous round is at <20181209200449.16342-1-t.gummerer@gmail.com>.\n\nThanks Junio, Duy and Elijah for your comments and suggestions on the\nprevious round.\n\nThis round drops the last three patches from the previous round,\nnamely introducing a \"--cached\" and a \"--ignore-unmatched\" option, and\nusing the new no-overlay mode in \"git stash\".  The --ignore-unmatched\noption may not be necessary, while using the new mode in 'git stash'\nwill be done once the stash-in-C topic landed.\n\nIntroducing a --cached and --worktree-only (as suggested by Elijah)\noption can come in a future step, they are orthogonal to this topic.\n\nOther changes from v1:\n- Rebase onto the current master, so we can also move t2028 and t2029\n  to the t24xx range.\n- Add a comment clarifying why using the CE_WT_REMOVE flag and topath\n  in checkout_entry is a bug.\n- clarify a comment in checkout.c\n- factor out the function to mark a cache entry as CE_MATCHED, and\n  have separate such functions for overlay mode and no-overlay mode.\n  This should hopefully make the logic a bit easier to follow.\n- Adjust the commit message, justifying why we don't remove untracked\n  files even in the new no-overlay mode.\n- add documentation for the new feature\n- document that -p defaults to no overlay mode, and cannot be used\n  with overlay mode.\n- add a config option checkout.overlayMode, so overlay mode can be\n  turned on by default.\n\nRange-diff can be found after the diffstat.\n\nThomas Gummerer (8):\n  move worktree tests to t24*\n  entry: factor out unlink_entry function\n  entry: support CE_WT_REMOVE flag in checkout_entry\n  read-cache: add invalidate parameter to remove_marked_cache_entries\n  checkout: clarify comment\n  checkout: factor out mark_cache_entry_for_checkout function\n  checkout: introduce --{,no-}overlay option\n  checkout: introduce checkout.overlayMode config\n\n Documentation/config/checkout.txt             |   7 +\n Documentation/git-checkout.txt                |  10 ++\n builtin/checkout.c                            | 133 +++++++++++++-----\n cache.h                                       |   7 +-\n entry.c                                       |  26 ++++\n read-cache.c                                  |   8 +-\n split-index.c                                 |   2 +-\n t/t2025-checkout-no-overlay.sh                |  57 ++++++++\n ...-worktree-add.sh => t2400-worktree-add.sh} |   0\n ...ktree-prune.sh => t2401-worktree-prune.sh} |   0\n ...orktree-list.sh => t2402-worktree-list.sh} |   0\n ...orktree-move.sh => t2403-worktree-move.sh} |   0\n ...ree-config.sh => t2404-worktree-config.sh} |   0\n t/t9902-completion.sh                         |   1 +\n unpack-trees.c                                |  21 +--\n 15 files changed, 213 insertions(+), 59 deletions(-)\n create mode 100755 t/t2025-checkout-no-overlay.sh\n rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n rename t/{t2028-worktree-move.sh => t2403-worktree-move.sh} (100%)\n rename t/{t2029-worktree-config.sh => t2404-worktree-config.sh} (100%)\n\n1:  70bd75b202 ! 1:  fa450cda7c move worktree tests to t24*\n    @@ -29,3 +29,13 @@\n      similarity index 100%\n      rename from t/t2027-worktree-list.sh\n      rename to t/t2402-worktree-list.sh\n    +\n    + diff --git a/t/t2028-worktree-move.sh b/t/t2403-worktree-move.sh\n    + similarity index 100%\n    + rename from t/t2028-worktree-move.sh\n    + rename to t/t2403-worktree-move.sh\n    +\n    + diff --git a/t/t2029-worktree-config.sh b/t/t2404-worktree-config.sh\n    + similarity index 100%\n    + rename from t/t2029-worktree-config.sh\n    + rename to t/t2404-worktree-config.sh\n2:  0fd9be987d = 2:  9ada8d3484 entry: factor out unlink_entry function\n3:  4d6112b112 ! 3:  41c0ea4047 entry: support CE_WT_REMOVE flag in checkout_entry\n    @@ -22,6 +22,10 @@\n      \n     +\tif (ce->ce_flags & CE_WT_REMOVE) {\n     +\t\tif (topath)\n    ++\t\t\t/*\n    ++\t\t\t * No content and thus no path to create, so we have\n    ++\t\t\t * no pathname to return.\n    ++\t\t\t */\n     +\t\t\tBUG(\"Can't remove entry to a path\");\n     +\t\tunlink_entry(ce);\n     +\t\treturn 0;\n4:  6e9f68b8f1 ! 4:  afccb0848d read-cache: add invalidate parameter to remove_marked_cache_entries\n    @@ -11,6 +11,10 @@\n         function will take care of invalidating the path in the cache tree and\n         in the untracked cache.\n     \n    +    Note that the current callsites already do the invalidation properly\n    +    in other places, so we're just passing 0 from there to keep the status\n    +    quo.\n    +\n         This will be useful in a subsequent commit.\n     \n         Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n-:  ---------- > 5:  8a2b5efdad checkout: clarify comment\n-:  ---------- > 6:  c405f20471 checkout: factor out mark_cache_entry_for_checkout function\n5:  4a7670d34c ! 7:  e5b18bcd02 checkout: introduce --{,no-}overlay option\n    @@ -17,8 +17,43 @@\n         'git checkout --overlay -p' to avoid confusing users who would expect\n         to be able to force overlay mode in 'git checkout -p' this way.\n     \n    +    Untracked files are not affected by this change, so 'git checkout\n    +    --no-overlay HEAD -- untracked' will not remove untracked from the\n    +    working tree.  This is so e.g. 'git checkout --no-overlay HEAD -- dir/'\n    +    doesn't delete all untracked files in dir/, but rather just resets the\n    +    state of files that are known to git.\n    +\n    +    Suggested-by: Junio C Hamano <gitster@pobox.com>\n         Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n     \n    + diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\n    + --- a/Documentation/git-checkout.txt\n    + +++ b/Documentation/git-checkout.txt\n    +@@\n    + This means that you can use `git checkout -p` to selectively discard\n    + edits from your current working tree. See the ``Interactive Mode''\n    + section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n    +++\n    ++Note that this option uses the no overlay mode by default (see also\n    ++-`--[no-]overlay`), and currently doesn't support overlay mode.\n    + \n    + --ignore-other-worktrees::\n    + \t`git checkout` refuses when the wanted ref is already checked\n    +@@\n    + \tJust like linkgit:git-submodule[1], this will detach the\n    + \tsubmodules HEAD.\n    + \n    ++--[no-]overlay::\n    ++\tIn the default overlay mode files `git checkout` never\n    ++\tremoves files from the index or the working tree.  When\n    ++\tspecifying --no-overlay, files that appear in the index and\n    ++\tworking tree, but not in <tree-ish> are removed, to make them\n    ++\tmatch <tree-ish> exactly.\n    ++\n    + <branch>::\n    + \tBranch to checkout; if it refers to a branch (i.e., a name that,\n    + \twhen prepended with \"refs/heads/\", is a valid ref), then that\n    +\n      diff --git a/builtin/checkout.c b/builtin/checkout.c\n      --- a/builtin/checkout.c\n      +++ b/builtin/checkout.c\n    @@ -70,44 +105,60 @@\n      \t\treturn error(_(\"path '%s' does not have our version\"), ce->name);\n      \telse\n     @@\n    - \t\tce->ce_flags &= ~CE_MATCHED;\n    - \t\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n    - \t\t\tcontinue;\n    --\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n    --\t\t\t/*\n    --\t\t\t * \"git checkout tree-ish -- path\", but this entry\n    --\t\t\t * is in the original index; it will not be checked\n    --\t\t\t * out to the working tree and it does not matter\n    --\t\t\t * if pathspec matched this entry.  We will not do\n    --\t\t\t * anything to this entry at all.\n    --\t\t\t */\n    --\t\t\tcontinue;\n    -+\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE)) {\n    -+\t\t\tif (!opts->overlay_mode &&\n    -+\t\t\t    ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {\n    -+\t\t\t\t/*\n    -+\t\t\t\t * \"git checkout --no-overlay <tree-ish> -- path\",\n    -+\t\t\t\t * and the path is not in tree-ish, but is in\n    -+\t\t\t\t * the current index, which means that it should \n    -+\t\t\t\t * be removed.\n    -+\t\t\t\t */\n    -+\t\t\t\tce->ce_flags |= CE_MATCHED | CE_REMOVE | CE_WT_REMOVE;\n    -+\t\t\t\tcontinue;\n    -+\t\t\t} else {\n    -+\t\t\t\t/*\n    -+\t\t\t\t * \"git checkout tree-ish -- path\", but this\n    -+\t\t\t\t * entry is in the original index; it will not\n    -+\t\t\t\t * be checked out to the working tree and it\n    -+\t\t\t\t * does not matter if pathspec matched this\n    -+\t\t\t\t * entry.  We will not do anything to this entry\n    -+\t\t\t\t * at all.\n    -+\t\t\t\t */\n    -+\t\t\t\tcontinue;\n    -+\t\t\t}\n    -+\t\t}\n    - \t\t/*\n    - \t\t * Either this entry came from the tree-ish we are\n    - \t\t * checking the paths out of, or we are checking out\n    + \treturn status;\n    + }\n    + \n    +-static void mark_ce_for_checkout(struct cache_entry *ce,\n    +-\t\t\t\t char *ps_matched,\n    +-\t\t\t\t const struct checkout_opts *opts)\n    ++static void mark_ce_for_checkout_overlay(struct cache_entry *ce,\n    ++\t\t\t\t\t char *ps_matched,\n    ++\t\t\t\t\t const struct checkout_opts *opts)\n    + {\n    + \tce->ce_flags &= ~CE_MATCHED;\n    + \tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n    +@@\n    + \t\tce->ce_flags |= CE_MATCHED;\n    + }\n    + \n    ++static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,\n    ++\t\t\t\t\t    char *ps_matched,\n    ++\t\t\t\t\t    const struct checkout_opts *opts)\n    ++{\n    ++\tce->ce_flags &= ~CE_MATCHED;\n    ++\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n    ++\t\treturn;\n    ++\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {\n    ++\t\tce->ce_flags |= CE_MATCHED;\n    ++\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n    ++\t\t\t/*\n    ++\t\t\t * In overlay mode, but the path is not in\n    ++\t\t\t * tree-ish, which means we should remove it\n    ++\t\t\t * from the index and the working tree.\n    ++\t\t\t */\n    ++\t\t\tce->ce_flags |= CE_REMOVE | CE_WT_REMOVE;\n    ++\t}\n    ++}\n    ++\n    + static int checkout_paths(const struct checkout_opts *opts,\n    + \t\t\t  const char *revision)\n    + {\n    +@@\n    + \t * to be checked out.\n    + \t */\n    + \tfor (pos = 0; pos < active_nr; pos++)\n    +-\t\tmark_ce_for_checkout(active_cache[pos], ps_matched, opts);\n    ++\t\tif (opts->overlay_mode)\n    ++\t\t\tmark_ce_for_checkout_overlay(active_cache[pos],\n    ++\t\t\t\t\t\t     ps_matched,\n    ++\t\t\t\t\t\t     opts);\n    ++\t\telse\n    ++\t\t\tmark_ce_for_checkout_no_overlay(active_cache[pos],\n    ++\t\t\t\t\t\t\tps_matched,\n    ++\t\t\t\t\t\t\topts);\n    + \n    + \tif (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {\n    + \t\tfree(ps_matched);\n     @@\n      \t\t\tif (opts->force) {\n      \t\t\t\twarning(_(\"path '%s' is unmerged\"), ce->name);\n    @@ -160,7 +211,7 @@\n      \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n      \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n      \t\tOPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n    -+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode\")),\n    ++\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode (default)\")),\n      \t\tOPT_END(),\n      \t};\n      \n    @@ -198,7 +249,7 @@\n     +\tgit commit --allow-empty -m \"initial\"\n     +'\n     +\n    -+test_expect_success 'checkout --no-overlay deletes files not in <tree>' '\n    ++test_expect_success 'checkout --no-overlay deletes files not in <tree-ish>' '\n     +\t>file &&\n     +\tmkdir dir &&\n     +\t>dir/file1 &&\n    @@ -218,7 +269,7 @@\n     +\ttest_i18ngrep \"fatal: -p and --overlay are mutually exclusive\" actual\n     +'\n     +\n    -+test_expect_success '--no-overlay --theirs with M/D conflict deletes file' '\n    ++test_expect_success '--no-overlay --theirs with D/F conflict deletes file' '\n     +\ttest_commit file1 file1 &&\n     +\ttest_commit file2 file2 &&\n     +\tgit rm --cached file1 &&\n6:  695b671675 < -:  ---------- checkout: add --cached option\n7:  d0b5a356b2 < -:  ---------- checkout: allow ignoring unmatched pathspec\n8:  0a4565acc1 < -:  ---------- stash: use git checkout --no-overlay\n-:  ---------- > 8:  de24990d57 checkout: introduce checkout.overlayMode config\n\n-- \n2.20.1.415.g653613c723\n"},{"id":"365634","messageId":"20181220134820.21810-2-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v2 1/8] move worktree tests to t24*","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:13Z","receivedAt":"2018-12-20T13:48:42Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"The 'git worktree' command used to be just another mode in 'git\ncheckout', namely 'git checkout --to'.  When the tests for the latter\nwere retrofitted for the former, the test name was adjusted, but the\ntest number was kept, even though the test is testing a different\ncommand now.  t/README states: \"Second digit tells the particular\ncommand we are testing.\", so 'git worktree' should have a separate\nnumber just for itself.\n\nMove the worktree tests to t24* to adhere to that guideline. We're\ngoing to make use of the free'd up numbers in a subsequent commit.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n t/{t2025-worktree-add.sh => t2400-worktree-add.sh}       | 0\n t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh}   | 0\n t/{t2027-worktree-list.sh => t2402-worktree-list.sh}     | 0\n t/{t2028-worktree-move.sh => t2403-worktree-move.sh}     | 0\n t/{t2029-worktree-config.sh => t2404-worktree-config.sh} | 0\n 5 files changed, 0 insertions(+), 0 deletions(-)\n rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n rename t/{t2028-worktree-move.sh => t2403-worktree-move.sh} (100%)\n rename t/{t2029-worktree-config.sh => t2404-worktree-config.sh} (100%)\n\ndiff --git a/t/t2025-worktree-add.sh b/t/t2400-worktree-add.sh\nsimilarity index 100%\nrename from t/t2025-worktree-add.sh\nrename to t/t2400-worktree-add.sh\ndiff --git a/t/t2026-worktree-prune.sh b/t/t2401-worktree-prune.sh\nsimilarity index 100%\nrename from t/t2026-worktree-prune.sh\nrename to t/t2401-worktree-prune.sh\ndiff --git a/t/t2027-worktree-list.sh b/t/t2402-worktree-list.sh\nsimilarity index 100%\nrename from t/t2027-worktree-list.sh\nrename to t/t2402-worktree-list.sh\ndiff --git a/t/t2028-worktree-move.sh b/t/t2403-worktree-move.sh\nsimilarity index 100%\nrename from t/t2028-worktree-move.sh\nrename to t/t2403-worktree-move.sh\ndiff --git a/t/t2029-worktree-config.sh b/t/t2404-worktree-config.sh\nsimilarity index 100%\nrename from t/t2029-worktree-config.sh\nrename to t/t2404-worktree-config.sh\n-- \n2.20.1.415.g653613c723\n\n"},{"id":"365635","messageId":"20181220134820.21810-3-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v2 2/8] entry: factor out unlink_entry function","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:14Z","receivedAt":"2018-12-20T13:48:43Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Factor out the 'unlink_entry()' function from unpack-trees.c to\nentry.c.  It will be used in other places as well in subsequent\nsteps.\n\nAs it's no longer a static function, also move the documentation to\nthe header file to make it more discoverable.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n cache.h        |  5 +++++\n entry.c        | 15 +++++++++++++++\n unpack-trees.c | 19 -------------------\n 3 files changed, 20 insertions(+), 19 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ca36b44ee0..c1c953e810 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1542,6 +1542,11 @@ struct checkout {\n extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);\n extern void enable_delayed_checkout(struct checkout *state);\n extern int finish_delayed_checkout(struct checkout *state);\n+/*\n+ * Unlink the last component and schedule the leading directories for\n+ * removal, such that empty directories get removed.\n+ */\n+extern void unlink_entry(const struct cache_entry *ce);\n \n struct cache_def {\n \tstruct strbuf path;\ndiff --git a/entry.c b/entry.c\nindex 0a3c451f5f..b9eef57117 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -508,3 +508,18 @@ int checkout_entry(struct cache_entry *ce,\n \tcreate_directories(path.buf, path.len, state);\n \treturn write_entry(ce, path.buf, state, 0);\n }\n+\n+void unlink_entry(const struct cache_entry *ce)\n+{\n+\tconst struct submodule *sub = submodule_from_ce(ce);\n+\tif (sub) {\n+\t\t/* state.force is set at the caller. */\n+\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n+\t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n+\t}\n+\tif (!check_leading_path(ce->name, ce_namelen(ce)))\n+\t\treturn;\n+\tif (remove_or_warn(ce->ce_mode, ce->name))\n+\t\treturn;\n+\tschedule_dir_for_removal(ce->name, ce_namelen(ce));\n+}\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 7570df481b..e8d1a6ac50 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -300,25 +300,6 @@ static void load_gitmodules_file(struct index_state *index,\n \t}\n }\n \n-/*\n- * Unlink the last component and schedule the leading directories for\n- * removal, such that empty directories get removed.\n- */\n-static void unlink_entry(const struct cache_entry *ce)\n-{\n-\tconst struct submodule *sub = submodule_from_ce(ce);\n-\tif (sub) {\n-\t\t/* state.force is set at the caller. */\n-\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n-\t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n-\t}\n-\tif (!check_leading_path(ce->name, ce_namelen(ce)))\n-\t\treturn;\n-\tif (remove_or_warn(ce->ce_mode, ce->name))\n-\t\treturn;\n-\tschedule_dir_for_removal(ce->name, ce_namelen(ce));\n-}\n-\n static struct progress *get_progress(struct unpack_trees_options *o)\n {\n \tunsigned cnt = 0, total = 0;\n-- \n2.20.1.415.g653613c723\n\n"},{"id":"365636","messageId":"20181220134820.21810-4-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v2 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:15Z","receivedAt":"2018-12-20T13:48:46Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"'checkout_entry()' currently only supports creating new entries in the\nworking tree, but not deleting them.  Add the ability to remove\nentries at the same time if the entry is marked with the CE_WT_REMOVE\nflag.\n\nCurrently this doesn't have any effect, as the CE_WT_REMOVE flag is\nonly used in unpack-tree, however we will make use of this in a\nsubsequent step in the series.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n entry.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/entry.c b/entry.c\nindex b9eef57117..3d3701e7ae 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -441,6 +441,17 @@ int checkout_entry(struct cache_entry *ce,\n \tstatic struct strbuf path = STRBUF_INIT;\n \tstruct stat st;\n \n+\tif (ce->ce_flags & CE_WT_REMOVE) {\n+\t\tif (topath)\n+\t\t\t/*\n+\t\t\t * No content and thus no path to create, so we have\n+\t\t\t * no pathname to return.\n+\t\t\t */\n+\t\t\tBUG(\"Can't remove entry to a path\");\n+\t\tunlink_entry(ce);\n+\t\treturn 0;\n+\t}\n+\n \tif (topath)\n \t\treturn write_entry(ce, topath, state, 1);\n \n-- \n2.20.1.415.g653613c723\n\n"},{"id":"365637","messageId":"20181220134820.21810-5-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v2 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:16Z","receivedAt":"2018-12-20T13:48:49Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"When marking cache entries for removal, and later removing them all at\nonce using 'remove_marked_cache_entries()', cache entries currently\nhave to be invalidated manually in the cache tree and in the untracked\ncache.\n\nAdd an invalidate flag to the function.  With the flag set, the\nfunction will take care of invalidating the path in the cache tree and\nin the untracked cache.\n\nNote that the current callsites already do the invalidation properly\nin other places, so we're just passing 0 from there to keep the status\nquo.\n\nThis will be useful in a subsequent commit.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n cache.h        | 2 +-\n read-cache.c   | 8 +++++++-\n split-index.c  | 2 +-\n unpack-trees.c | 2 +-\n 4 files changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c1c953e810..1deee48f5b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -751,7 +751,7 @@ extern void rename_index_entry_at(struct index_state *, int pos, const char *new\n /* Remove entry, return true if there are more entries to go. */\n extern int remove_index_entry_at(struct index_state *, int pos);\n \n-extern void remove_marked_cache_entries(struct index_state *istate);\n+extern void remove_marked_cache_entries(struct index_state *istate, int invalidate);\n extern int remove_file_from_index(struct index_state *, const char *path);\n #define ADD_CACHE_VERBOSE 1\n #define ADD_CACHE_PRETEND 2\ndiff --git a/read-cache.c b/read-cache.c\nindex bd45dc3e24..978d43f676 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -590,13 +590,19 @@ int remove_index_entry_at(struct index_state *istate, int pos)\n  * CE_REMOVE is set in ce_flags.  This is much more effective than\n  * calling remove_index_entry_at() for each entry to be removed.\n  */\n-void remove_marked_cache_entries(struct index_state *istate)\n+void remove_marked_cache_entries(struct index_state *istate, int invalidate)\n {\n \tstruct cache_entry **ce_array = istate->cache;\n \tunsigned int i, j;\n \n \tfor (i = j = 0; i < istate->cache_nr; i++) {\n \t\tif (ce_array[i]->ce_flags & CE_REMOVE) {\n+\t\t\tif (invalidate) {\n+\t\t\t\tcache_tree_invalidate_path(istate,\n+\t\t\t\t\t\t\t   ce_array[i]->name);\n+\t\t\t\tuntracked_cache_remove_from_index(istate,\n+\t\t\t\t\t\t\t\t  ce_array[i]->name);\n+\t\t\t}\n \t\t\tremove_name_hash(istate, ce_array[i]);\n \t\t\tsave_or_free_index_entry(istate, ce_array[i]);\n \t\t}\ndiff --git a/split-index.c b/split-index.c\nindex 5820412dc5..8aebc3661b 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -162,7 +162,7 @@ void merge_base_index(struct index_state *istate)\n \tewah_each_bit(si->replace_bitmap, replace_entry, istate);\n \tewah_each_bit(si->delete_bitmap, mark_entry_for_delete, istate);\n \tif (si->nr_deletions)\n-\t\tremove_marked_cache_entries(istate);\n+\t\tremove_marked_cache_entries(istate, 0);\n \n \tfor (i = si->nr_replacements; i < si->saved_cache_nr; i++) {\n \t\tif (!ce_namelen(si->saved_cache[i]))\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex e8d1a6ac50..8e6afa924d 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -392,7 +392,7 @@ static int check_updates(struct unpack_trees_options *o)\n \t\t\t\tunlink_entry(ce);\n \t\t}\n \t}\n-\tremove_marked_cache_entries(index);\n+\tremove_marked_cache_entries(index, 0);\n \tremove_scheduled_dirs();\n \n \tif (should_update_submodules() && o->update && !o->dry_run)\n-- \n2.20.1.415.g653613c723\n\n"},{"id":"365638","messageId":"20181220134820.21810-6-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v2 5/8] checkout: clarify comment","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:17Z","receivedAt":"2018-12-20T13:48:50Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"The key point for the if statement is that read_tree_some did not\nupdate the entry, because either it doesn't exist in tree-ish or\ndoesn't match the pathspec.  Clarify that.\n\nSuggested-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n builtin/checkout.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex acdafc6e4c..cb166b2e07 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -304,10 +304,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\tcontinue;\n \t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n \t\t\t/*\n-\t\t\t * \"git checkout tree-ish -- path\", but this entry\n-\t\t\t * is in the original index; it will not be checked\n-\t\t\t * out to the working tree and it does not matter\n-\t\t\t * if pathspec matched this entry.  We will not do\n+\t\t\t * \"git checkout tree-ish -- path\" and this entry\n+\t\t\t * is in the original index, but is not in tree-ish\n+\t\t\t * or does not match the pathspec; it will not be\n+\t\t\t * checked out to the working tree.  We will not do\n \t\t\t * anything to this entry at all.\n \t\t\t */\n \t\t\tcontinue;\n-- \n2.20.1.415.g653613c723\n\n"},{"id":"365639","messageId":"20181220134820.21810-7-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v2 6/8] checkout: factor out mark_cache_entry_for_checkout function","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:18Z","receivedAt":"2018-12-20T13:48:52Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Factor out the code that marks a cache entry as matched for checkout\ninto a separate function.  We are going to introduce a new mode in\n'git checkout' in a subsequent commit, that is going to have a\nslightly different logic.  This would make this code unnecessarily\ncomplex.\n\nMoving that complexity into separate functions will make the code in\nthe subsequent step easier to follow.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n builtin/checkout.c | 67 +++++++++++++++++++++++++---------------------\n 1 file changed, 36 insertions(+), 31 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex cb166b2e07..32c4b7f897 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -247,6 +247,40 @@ static int checkout_merged(int pos, const struct checkout *state)\n \treturn status;\n }\n \n+static void mark_ce_for_checkout(struct cache_entry *ce,\n+\t\t\t\t char *ps_matched,\n+\t\t\t\t const struct checkout_opts *opts)\n+{\n+\tce->ce_flags &= ~CE_MATCHED;\n+\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n+\t\treturn;\n+\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n+\t\t/*\n+\t\t * \"git checkout tree-ish -- path\", but this entry\n+\t\t * is in the original index but is not in tree-ish\n+\t\t * or does not match the pathspec; it will not be\n+\t\t * checked out to the working tree.  We will not do\n+\t\t * anything to this entry at all.\n+\t\t */\n+\t\treturn;\n+\t/*\n+\t * Either this entry came from the tree-ish we are\n+\t * checking the paths out of, or we are checking out\n+\t * of the index.\n+\t *\n+\t * If it comes from the tree-ish, we already know it\n+\t * matches the pathspec and could just stamp\n+\t * CE_MATCHED to it from update_some(). But we still\n+\t * need ps_matched and read_tree_recursive (and\n+\t * eventually tree_entry_interesting) cannot fill\n+\t * ps_matched yet. Once it can, we can avoid calling\n+\t * match_pathspec() for _all_ entries when\n+\t * opts->source_tree != NULL.\n+\t */\n+\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))\n+\t\tce->ce_flags |= CE_MATCHED;\n+}\n+\n static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t  const char *revision)\n {\n@@ -297,37 +331,8 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t * Make sure all pathspecs participated in locating the paths\n \t * to be checked out.\n \t */\n-\tfor (pos = 0; pos < active_nr; pos++) {\n-\t\tstruct cache_entry *ce = active_cache[pos];\n-\t\tce->ce_flags &= ~CE_MATCHED;\n-\t\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n-\t\t\tcontinue;\n-\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n-\t\t\t/*\n-\t\t\t * \"git checkout tree-ish -- path\" and this entry\n-\t\t\t * is in the original index, but is not in tree-ish\n-\t\t\t * or does not match the pathspec; it will not be\n-\t\t\t * checked out to the working tree.  We will not do\n-\t\t\t * anything to this entry at all.\n-\t\t\t */\n-\t\t\tcontinue;\n-\t\t/*\n-\t\t * Either this entry came from the tree-ish we are\n-\t\t * checking the paths out of, or we are checking out\n-\t\t * of the index.\n-\t\t *\n-\t\t * If it comes from the tree-ish, we already know it\n-\t\t * matches the pathspec and could just stamp\n-\t\t * CE_MATCHED to it from update_some(). But we still\n-\t\t * need ps_matched and read_tree_recursive (and\n-\t\t * eventually tree_entry_interesting) cannot fill\n-\t\t * ps_matched yet. Once it can, we can avoid calling\n-\t\t * match_pathspec() for _all_ entries when\n-\t\t * opts->source_tree != NULL.\n-\t\t */\n-\t\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))\n-\t\t\tce->ce_flags |= CE_MATCHED;\n-\t}\n+\tfor (pos = 0; pos < active_nr; pos++)\n+\t\tmark_ce_for_checkout(active_cache[pos], ps_matched, opts);\n \n \tif (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {\n \t\tfree(ps_matched);\n-- \n2.20.1.415.g653613c723\n\n"},{"id":"365640","messageId":"20181220134820.21810-8-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v2 7/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:19Z","receivedAt":"2018-12-20T13:48:54Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git checkout' is defined as an overlay operation, which\nmeans that if in 'git checkout <tree-ish> -- [<pathspec>]' we have an\nentry in the index that matches <pathspec>, but that doesn't exist in\n<tree-ish>, that entry will not be removed from the index or the\nworking tree.\n\nIntroduce a new --{,no-}overlay option, which allows using 'git\ncheckout' in non-overlay mode, thus removing files from the working\ntree if they do not exist in <tree-ish> but match <pathspec>.\n\nNote that 'git checkout -p <tree-ish> -- [<pathspec>]' already works\nthis way, so no changes are needed for the patch mode.  We disallow\n'git checkout --overlay -p' to avoid confusing users who would expect\nto be able to force overlay mode in 'git checkout -p' this way.\n\nUntracked files are not affected by this change, so 'git checkout\n--no-overlay HEAD -- untracked' will not remove untracked from the\nworking tree.  This is so e.g. 'git checkout --no-overlay HEAD -- dir/'\ndoesn't delete all untracked files in dir/, but rather just resets the\nstate of files that are known to git.\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-checkout.txt | 10 ++++++\n builtin/checkout.c             | 66 +++++++++++++++++++++++++++++-----\n t/t2025-checkout-no-overlay.sh | 47 ++++++++++++++++++++++++\n t/t9902-completion.sh          |  1 +\n 4 files changed, 116 insertions(+), 8 deletions(-)\n create mode 100755 t/t2025-checkout-no-overlay.sh\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 801de2f764..4ac8c55865 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -260,6 +260,9 @@ the conflicted merge in the specified paths.\n This means that you can use `git checkout -p` to selectively discard\n edits from your current working tree. See the ``Interactive Mode''\n section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n++\n+Note that this option uses the no overlay mode by default (see also\n+-`--[no-]overlay`), and currently doesn't support overlay mode.\n \n --ignore-other-worktrees::\n \t`git checkout` refuses when the wanted ref is already checked\n@@ -276,6 +279,13 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n \tJust like linkgit:git-submodule[1], this will detach the\n \tsubmodules HEAD.\n \n+--[no-]overlay::\n+\tIn the default overlay mode files `git checkout` never\n+\tremoves files from the index or the working tree.  When\n+\tspecifying --no-overlay, files that appear in the index and\n+\tworking tree, but not in <tree-ish> are removed, to make them\n+\tmatch <tree-ish> exactly.\n+\n <branch>::\n \tBranch to checkout; if it refers to a branch (i.e., a name that,\n \twhen prepended with \"refs/heads/\", is a valid ref), then that\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 32c4b7f897..0c5fe948ef 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -44,6 +44,7 @@ struct checkout_opts {\n \tint ignore_skipworktree;\n \tint ignore_other_worktrees;\n \tint show_progress;\n+\tint overlay_mode;\n \t/*\n \t * If new checkout options are added, skip_merge_working_tree\n \t * should be updated accordingly.\n@@ -132,7 +133,8 @@ static int skip_same_name(const struct cache_entry *ce, int pos)\n \treturn pos;\n }\n \n-static int check_stage(int stage, const struct cache_entry *ce, int pos)\n+static int check_stage(int stage, const struct cache_entry *ce, int pos,\n+\t\t       int overlay_mode)\n {\n \twhile (pos < active_nr &&\n \t       !strcmp(active_cache[pos]->name, ce->name)) {\n@@ -140,6 +142,8 @@ static int check_stage(int stage, const struct cache_entry *ce, int pos)\n \t\t\treturn 0;\n \t\tpos++;\n \t}\n+\tif (!overlay_mode)\n+\t\treturn 0;\n \tif (stage == 2)\n \t\treturn error(_(\"path '%s' does not have our version\"), ce->name);\n \telse\n@@ -165,7 +169,7 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)\n }\n \n static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n-\t\t\t  const struct checkout *state)\n+\t\t\t  const struct checkout *state, int overlay_mode)\n {\n \twhile (pos < active_nr &&\n \t       !strcmp(active_cache[pos]->name, ce->name)) {\n@@ -173,6 +177,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n \t\t\treturn checkout_entry(active_cache[pos], state, NULL);\n \t\tpos++;\n \t}\n+\tif (!overlay_mode) {\n+\t\tunlink_entry(ce);\n+\t\treturn 0;\n+\t}\n \tif (stage == 2)\n \t\treturn error(_(\"path '%s' does not have our version\"), ce->name);\n \telse\n@@ -247,9 +255,9 @@ static int checkout_merged(int pos, const struct checkout *state)\n \treturn status;\n }\n \n-static void mark_ce_for_checkout(struct cache_entry *ce,\n-\t\t\t\t char *ps_matched,\n-\t\t\t\t const struct checkout_opts *opts)\n+static void mark_ce_for_checkout_overlay(struct cache_entry *ce,\n+\t\t\t\t\t char *ps_matched,\n+\t\t\t\t\t const struct checkout_opts *opts)\n {\n \tce->ce_flags &= ~CE_MATCHED;\n \tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n@@ -281,6 +289,25 @@ static void mark_ce_for_checkout(struct cache_entry *ce,\n \t\tce->ce_flags |= CE_MATCHED;\n }\n \n+static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,\n+\t\t\t\t\t    char *ps_matched,\n+\t\t\t\t\t    const struct checkout_opts *opts)\n+{\n+\tce->ce_flags &= ~CE_MATCHED;\n+\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n+\t\treturn;\n+\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {\n+\t\tce->ce_flags |= CE_MATCHED;\n+\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n+\t\t\t/*\n+\t\t\t * In overlay mode, but the path is not in\n+\t\t\t * tree-ish, which means we should remove it\n+\t\t\t * from the index and the working tree.\n+\t\t\t */\n+\t\t\tce->ce_flags |= CE_REMOVE | CE_WT_REMOVE;\n+\t}\n+}\n+\n static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t  const char *revision)\n {\n@@ -332,7 +359,14 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t * to be checked out.\n \t */\n \tfor (pos = 0; pos < active_nr; pos++)\n-\t\tmark_ce_for_checkout(active_cache[pos], ps_matched, opts);\n+\t\tif (opts->overlay_mode)\n+\t\t\tmark_ce_for_checkout_overlay(active_cache[pos],\n+\t\t\t\t\t\t     ps_matched,\n+\t\t\t\t\t\t     opts);\n+\t\telse\n+\t\t\tmark_ce_for_checkout_no_overlay(active_cache[pos],\n+\t\t\t\t\t\t\tps_matched,\n+\t\t\t\t\t\t\topts);\n \n \tif (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {\n \t\tfree(ps_matched);\n@@ -353,7 +387,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\tif (opts->force) {\n \t\t\t\twarning(_(\"path '%s' is unmerged\"), ce->name);\n \t\t\t} else if (opts->writeout_stage) {\n-\t\t\t\terrs |= check_stage(opts->writeout_stage, ce, pos);\n+\t\t\t\terrs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode);\n \t\t\t} else if (opts->merge) {\n \t\t\t\terrs |= check_stages((1<<2) | (1<<3), ce, pos);\n \t\t\t} else {\n@@ -380,12 +414,14 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (opts->writeout_stage)\n-\t\t\t\terrs |= checkout_stage(opts->writeout_stage, ce, pos, &state);\n+\t\t\t\terrs |= checkout_stage(opts->writeout_stage, ce, pos, &state, opts->overlay_mode);\n \t\t\telse if (opts->merge)\n \t\t\t\terrs |= checkout_merged(pos, &state);\n \t\t\tpos = skip_same_name(ce, pos) - 1;\n \t\t}\n \t}\n+\tremove_marked_cache_entries(&the_index, 1);\n+\tremove_scheduled_dirs();\n \terrs |= finish_delayed_checkout(&state);\n \n \tif (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))\n@@ -547,6 +583,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,\n \t * opts->show_progress only impacts output so doesn't require a merge\n \t */\n \n+\t/*\n+\t * opts->overlay_mode cannot be used with switching branches so is\n+\t * not tested here\n+\t */\n+\n \t/*\n \t * If we aren't creating a new branch any changes or updates will\n \t * happen in the existing branch.  Since that could only be updating\n@@ -1183,6 +1224,10 @@ static int checkout_branch(struct checkout_opts *opts,\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n \t\t    \"--patch\");\n \n+\tif (!opts->overlay_mode)\n+\t\tdie(_(\"'%s' cannot be used with switching branches\"),\n+\t\t    \"--no-overlay\");\n+\n \tif (opts->writeout_stage)\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n \t\t    \"--ours/--theirs\");\n@@ -1271,6 +1316,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n \t\tOPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode (default)\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1279,6 +1325,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \topts.overwrite_ignore = 1;\n \topts.prefix = prefix;\n \topts.show_progress = -1;\n+\topts.overlay_mode = -1;\n \n \tgit_config(git_checkout_config, &opts);\n \n@@ -1302,6 +1349,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tif ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)\n \t\tdie(_(\"-b, -B and --orphan are mutually exclusive\"));\n \n+\tif (opts.overlay_mode == 1 && opts.patch_mode)\n+\t\tdie(_(\"-p and --overlay are mutually exclusive\"));\n+\n \t/*\n \t * From here on, new_branch will contain the branch to be checked out,\n \t * and new_branch_force and new_orphan_branch will tell us which one of\ndiff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh\nnew file mode 100755\nindex 0000000000..76330cb5ab\n--- /dev/null\n+++ b/t/t2025-checkout-no-overlay.sh\n@@ -0,0 +1,47 @@\n+#!/bin/sh\n+\n+test_description='checkout --no-overlay <tree-ish> -- <pathspec>'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\tgit commit --allow-empty -m \"initial\"\n+'\n+\n+test_expect_success 'checkout --no-overlay deletes files not in <tree-ish>' '\n+\t>file &&\n+\tmkdir dir &&\n+\t>dir/file1 &&\n+\tgit add file dir/file1 &&\n+\tgit checkout --no-overlay HEAD -- file &&\n+\ttest_path_is_missing file &&\n+\ttest_path_is_file dir/file1\n+'\n+\n+test_expect_success 'checkout --no-overlay removing last file from directory' '\n+\tgit checkout --no-overlay HEAD -- dir/file1 &&\n+\ttest_path_is_missing dir\n+'\n+\n+test_expect_success 'checkout -p --overlay is disallowed' '\n+\ttest_must_fail git checkout -p --overlay HEAD 2>actual &&\n+\ttest_i18ngrep \"fatal: -p and --overlay are mutually exclusive\" actual\n+'\n+\n+test_expect_success '--no-overlay --theirs with D/F conflict deletes file' '\n+\ttest_commit file1 file1 &&\n+\ttest_commit file2 file2 &&\n+\tgit rm --cached file1 &&\n+\techo 1234 >file1 &&\n+\tF1=$(git rev-parse HEAD:file1) &&\n+\tF2=$(git rev-parse HEAD:file2) &&\n+\t{\n+\t\techo \"100644 $F1 1\tfile1\" &&\n+\t\techo \"100644 $F2 2\tfile1\"\n+\t} | git update-index --index-info &&\n+\ttest_path_is_file file1 &&\n+\tgit checkout --theirs --no-overlay -- file1 &&\n+\ttest_path_is_missing file1\n+'\n+\n+test_done\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex d01ad8eb25..5758fffa0d 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1436,6 +1436,7 @@ test_expect_success 'double dash \"git checkout\"' '\n \t--progress Z\n \t--no-quiet Z\n \t--no-... Z\n+\t--overlay Z\n \tEOF\n '\n \n-- \n2.20.1.415.g653613c723\n\n"},{"id":"365641","messageId":"20181220134820.21810-9-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v2 8/8] checkout: introduce checkout.overlayMode config","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2018-12-20T13:48:20Z","receivedAt":"2018-12-20T13:48:57Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"In the previous patch we introduced a new no-overlay mode for git\ncheckout.  Some users (such as the author of this commit) may want to\nhave this mode turned on by default as it matches their mental model\nmore closely.  Make that possible by introducing a new config option\nto that extend.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/config/checkout.txt |  7 +++++++\n builtin/checkout.c                |  8 +++++++-\n t/t2025-checkout-no-overlay.sh    | 10 ++++++++++\n 3 files changed, 24 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config/checkout.txt b/Documentation/config/checkout.txt\nindex c4118fa196..53f917e15e 100644\n--- a/Documentation/config/checkout.txt\n+++ b/Documentation/config/checkout.txt\n@@ -21,3 +21,10 @@ checkout.optimizeNewBranch::\n \twill not update the skip-worktree bit in the index nor add/remove\n \tfiles in the working directory to reflect the current sparse checkout\n \tsettings nor will it show the local changes.\n+\n+checkout.overlayMode::\n+\tIn the default overlay mode files `git checkout` never\n+\tremoves files from the index or the working tree.  When\n+\tsetting checkout.overlayMode to false, files that appear in\n+\tthe index and working tree, but not in <tree-ish> are removed,\n+\tto make them match <tree-ish> exactly.\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 0c5fe948ef..b5dfc45736 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1019,13 +1019,19 @@ static int switch_branches(const struct checkout_opts *opts,\n \n static int git_checkout_config(const char *var, const char *value, void *cb)\n {\n+\tstruct checkout_opts *opts = cb;\n+\n \tif (!strcmp(var, \"checkout.optimizenewbranch\")) {\n \t\tcheckout_optimize_new_branch = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"checkout.overlaymode\")) {\n+\t\topts->overlay_mode = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \tif (!strcmp(var, \"diff.ignoresubmodules\")) {\n-\t\tstruct checkout_opts *opts = cb;\n \t\thandle_ignore_submodules_arg(&opts->diff_options, value);\n \t\treturn 0;\n \t}\ndiff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh\nindex 76330cb5ab..a4912e35cb 100755\n--- a/t/t2025-checkout-no-overlay.sh\n+++ b/t/t2025-checkout-no-overlay.sh\n@@ -44,4 +44,14 @@ test_expect_success '--no-overlay --theirs with D/F conflict deletes file' '\n \ttest_path_is_missing file1\n '\n \n+test_expect_success 'checkout with checkout.overlayMode=false deletes files not in <tree-ish>' '\n+\t>file &&\n+\tmkdir dir &&\n+\t>dir/file1 &&\n+\tgit add file dir/file1 &&\n+\tgit -c checkout.overlayMode=false checkout HEAD -- file &&\n+\ttest_path_is_missing file &&\n+\ttest_path_is_file dir/file1\n+'\n+\n test_done\n-- \n2.20.1.415.g653613c723\n\n"},{"id":"365758","messageId":"CACsJy8B-jB6o2XYG_6UdTrhrGbos-+5rs98qqQQuJYYV+6W+SQ@mail.gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-8-t.gummerer@gmail.com","subject":"Re: [PATCH v2 7/8] checkout: introduce --{,no-}overlay option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-12-23T08:05:07Z","receivedAt":"2018-12-23T08:05:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Dec 20, 2018 at 2:48 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\n> index 801de2f764..4ac8c55865 100644\n> --- a/Documentation/git-checkout.txt\n> +++ b/Documentation/git-checkout.txt\n> @@ -260,6 +260,9 @@ the conflicted merge in the specified paths.\n>  This means that you can use `git checkout -p` to selectively discard\n>  edits from your current working tree. See the ``Interactive Mode''\n>  section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n> ++\n> +Note that this option uses the no overlay mode by default (see also\n> +-`--[no-]overlay`), and currently doesn't support overlay mode.\n>\n>  --ignore-other-worktrees::\n>         `git checkout` refuses when the wanted ref is already checked\n> @@ -276,6 +279,13 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n>         Just like linkgit:git-submodule[1], this will detach the\n>         submodules HEAD.\n>\n> +--[no-]overlay::\n> +       In the default overlay mode files `git checkout` never\n\n-ECANTPARSE. Maybe \"files\" should be removed from this line?\n\n> +       removes files from the index or the working tree.  When\n> +       specifying --no-overlay, files that appear in the index and\n> +       working tree, but not in <tree-ish> are removed, to make them\n> +       match <tree-ish> exactly.\n> +\n>  <branch>::\n>         Branch to checkout; if it refers to a branch (i.e., a name that,\n>         when prepended with \"refs/heads/\", is a valid ref), then that\n-- \nDuy\n"},{"id":"365759","messageId":"CAPig+cSOyCQZXiG7sJWb12WzzujM-nsqqpt+cFZTFvXB1+-SVQ@mail.gmail.com","threadId":"49988","inReplyTo":"CACsJy8B-jB6o2XYG_6UdTrhrGbos-+5rs98qqQQuJYYV+6W+SQ@mail.gmail.com","subject":"Re: [PATCH v2 7/8] checkout: introduce --{,no-}overlay option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-12-23T09:44:37Z","receivedAt":"2018-12-23T09:44:51Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Dec 23, 2018 at 3:05 AM Duy Nguyen <pclouds@gmail.com> wrote:\n> On Thu, Dec 20, 2018 at 2:48 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > +--[no-]overlay::\n> > +       In the default overlay mode files `git checkout` never\n>\n> -ECANTPARSE. Maybe \"files\" should be removed from this line?\n\nAlso, add a comma after \"mode\".\n"},{"id":"366059","messageId":"xmqqo98yiq8i.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"20181220134820.21810-9-t.gummerer@gmail.com","subject":"Re: [PATCH v2 8/8] checkout: introduce checkout.overlayMode config","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-02T23:39:25Z","receivedAt":"2019-01-02T23:39:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> In the previous patch we introduced a new no-overlay mode for git\n> checkout.  Some users (such as the author of this commit) may want to\n> have this mode turned on by default as it matches their mental model\n> more closely.  Make that possible by introducing a new config option\n> to that extend.\n>\n> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> ---\n>  Documentation/config/checkout.txt |  7 +++++++\n>  builtin/checkout.c                |  8 +++++++-\n>  t/t2025-checkout-no-overlay.sh    | 10 ++++++++++\n>  3 files changed, 24 insertions(+), 1 deletion(-)\n>\n> diff --git a/Documentation/config/checkout.txt b/Documentation/config/checkout.txt\n> index c4118fa196..53f917e15e 100644\n> --- a/Documentation/config/checkout.txt\n> +++ b/Documentation/config/checkout.txt\n> @@ -21,3 +21,10 @@ checkout.optimizeNewBranch::\n>  \twill not update the skip-worktree bit in the index nor add/remove\n>  \tfiles in the working directory to reflect the current sparse checkout\n>  \tsettings nor will it show the local changes.\n> +\n> +checkout.overlayMode::\n> +\tIn the default overlay mode files `git checkout` never\n> +\tremoves files from the index or the working tree.\n\nTechnically the above \"never removes\" is incorrect.\n\n\t$ mv COPYING 1 && mkdir COPYING && mv 1 COPYING/COPYING\n\t$ git add COPYING\n\t$ git checkout HEAD COPYING\n\nwould remove COPYING/1 from the index and from the working tree to\nmake room.\n\nBecause I think that a bit of white lie like what you wrote would\nhelp readers understand the key point of \"overlay or not overlay\"\nbetter than an overly precise description of the reason why the\nremoval in the above three-liner case is the right thing to do, I\nthink the text in the patch is good enough at least for now, but I'd\nmention it in case somebody else can think of a better phrasing to\ncovey the same key point without being technically incorrect.\n\nThanks.\n"},{"id":"366221","messageId":"20190106181850.GG25639@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"CAPig+cSOyCQZXiG7sJWb12WzzujM-nsqqpt+cFZTFvXB1+-SVQ@mail.gmail.com","subject":"Re: [PATCH v2 7/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-06T18:18:50Z","receivedAt":"2019-01-06T18:18:54Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 12/23, Eric Sunshine wrote:\n> On Sun, Dec 23, 2018 at 3:05 AM Duy Nguyen <pclouds@gmail.com> wrote:\n> > On Thu, Dec 20, 2018 at 2:48 PM Thomas Gummerer <t.gummerer@gmail.com> wrote:\n> > > +--[no-]overlay::\n> > > +       In the default overlay mode files `git checkout` never\n> >\n> > -ECANTPARSE. Maybe \"files\" should be removed from this line?\n> \n> Also, add a comma after \"mode\".\n\nWill do, thanks both.\n"},{"id":"366223","messageId":"20190106183225.GH25639@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"xmqqo98yiq8i.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 8/8] checkout: introduce checkout.overlayMode config","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-06T18:32:25Z","receivedAt":"2019-01-06T18:32:31Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 01/02, Junio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n> \n> > In the previous patch we introduced a new no-overlay mode for git\n> > checkout.  Some users (such as the author of this commit) may want to\n> > have this mode turned on by default as it matches their mental model\n> > more closely.  Make that possible by introducing a new config option\n> > to that extend.\n> >\n> > Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n> > ---\n> >  Documentation/config/checkout.txt |  7 +++++++\n> >  builtin/checkout.c                |  8 +++++++-\n> >  t/t2025-checkout-no-overlay.sh    | 10 ++++++++++\n> >  3 files changed, 24 insertions(+), 1 deletion(-)\n> >\n> > diff --git a/Documentation/config/checkout.txt b/Documentation/config/checkout.txt\n> > index c4118fa196..53f917e15e 100644\n> > --- a/Documentation/config/checkout.txt\n> > +++ b/Documentation/config/checkout.txt\n> > @@ -21,3 +21,10 @@ checkout.optimizeNewBranch::\n> >  \twill not update the skip-worktree bit in the index nor add/remove\n> >  \tfiles in the working directory to reflect the current sparse checkout\n> >  \tsettings nor will it show the local changes.\n> > +\n> > +checkout.overlayMode::\n> > +\tIn the default overlay mode files `git checkout` never\n> > +\tremoves files from the index or the working tree.\n> \n> Technically the above \"never removes\" is incorrect.\n> \n> \t$ mv COPYING 1 && mkdir COPYING && mv 1 COPYING/COPYING\n> \t$ git add COPYING\n> \t$ git checkout HEAD COPYING\n> \n> would remove COPYING/1 from the index and from the working tree to\n> make room.\n\nRight, that's a case I didn't think about.\n\n> Because I think that a bit of white lie like what you wrote would\n> help readers understand the key point of \"overlay or not overlay\"\n> better than an overly precise description of the reason why the\n> removal in the above three-liner case is the right thing to do, I\n> think the text in the patch is good enough at least for now, but I'd\n> mention it in case somebody else can think of a better phrasing to\n> covey the same key point without being technically incorrect.\n\nMaybe it would be enough to say \"... `git checkout` never removes\nfiles, that are not in the tree being checked out, from the index or\nthe working tree\"?  It is more technically correct, but dunno making\nthe sentence harder to read is worth it.\n\n> Thanks.\n"},{"id":"366263","messageId":"xmqqy37w9zdc.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"20190106183225.GH25639@hank.intra.tgummerer.com","subject":"Re: [PATCH v2 8/8] checkout: introduce checkout.overlayMode config","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-07T17:00:31Z","receivedAt":"2019-01-07T17:00:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n> Maybe it would be enough to say \"... `git checkout` never removes\n> files, that are not in the tree being checked out, from the index or\n> the working tree\"?  It is more technically correct, but dunno making\n> the sentence harder to read is worth it.\n\nYeah, I share the same feeling.  Let's say the text in the posted\npatch is good enough and move on.\n\nThanks.\n"},{"id":"366371","messageId":"20190108215225.3077-1-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20181220134820.21810-1-t.gummerer@gmail.com","subject":"[PATCH v3 0/8] introduce no-overlay mode in git checkout","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:17Z","receivedAt":"2019-01-08T21:52:37Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Previous rounds are at <20181209200449.16342-1-t.gummerer@gmail.com>\nand <20181220134820.21810-1-t.gummerer@gmail.com>.\n\nThanks Duy, Eric and Junio for comments on the previous round.\n\nThis round fixes some inconsistencies and improves the grammar in the\ndocs.  Range-diff below:\n\n1:  fa450cda7c = 1:  fa450cda7c move worktree tests to t24*\n2:  9ada8d3484 = 2:  9ada8d3484 entry: factor out unlink_entry function\n3:  41c0ea4047 = 3:  41c0ea4047 entry: support CE_WT_REMOVE flag in checkout_entry\n4:  afccb0848d = 4:  afccb0848d read-cache: add invalidate parameter to remove_marked_cache_entries\n5:  8a2b5efdad = 5:  8a2b5efdad checkout: clarify comment\n6:  c405f20471 = 6:  c405f20471 checkout: factor out mark_cache_entry_for_checkout function\n7:  e5b18bcd02 ! 7:  a291dc78fa checkout: introduce --{,no-}overlay option\n    @@ -35,7 +35,7 @@\n      section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n     ++\n     +Note that this option uses the no overlay mode by default (see also\n    -+-`--[no-]overlay`), and currently doesn't support overlay mode.\n    ++`--[no-]overlay`), and currently doesn't support overlay mode.\n      \n      --ignore-other-worktrees::\n      \t`git checkout` refuses when the wanted ref is already checked\n    @@ -44,9 +44,9 @@\n      \tsubmodules HEAD.\n      \n     +--[no-]overlay::\n    -+\tIn the default overlay mode files `git checkout` never\n    ++\tIn the default overlay mode, `git checkout` never\n     +\tremoves files from the index or the working tree.  When\n    -+\tspecifying --no-overlay, files that appear in the index and\n    ++\tspecifying `--no-overlay`, files that appear in the index and\n     +\tworking tree, but not in <tree-ish> are removed, to make them\n     +\tmatch <tree-ish> exactly.\n     +\n8:  de24990d57 ! 8:  8d4070f142 checkout: introduce checkout.overlayMode config\n    @@ -19,9 +19,9 @@\n      \tsettings nor will it show the local changes.\n     +\n     +checkout.overlayMode::\n    -+\tIn the default overlay mode files `git checkout` never\n    ++\tIn the default overlay mode, `git checkout` never\n     +\tremoves files from the index or the working tree.  When\n    -+\tsetting checkout.overlayMode to false, files that appear in\n    ++\tsetting `checkout.overlayMode` to false, files that appear in\n     +\tthe index and working tree, but not in <tree-ish> are removed,\n     +\tto make them match <tree-ish> exactly.\n\nThomas Gummerer (8):\n  move worktree tests to t24*\n  entry: factor out unlink_entry function\n  entry: support CE_WT_REMOVE flag in checkout_entry\n  read-cache: add invalidate parameter to remove_marked_cache_entries\n  checkout: clarify comment\n  checkout: factor out mark_cache_entry_for_checkout function\n  checkout: introduce --{,no-}overlay option\n  checkout: introduce checkout.overlayMode config\n\n Documentation/config/checkout.txt             |   7 +\n Documentation/git-checkout.txt                |  10 ++\n builtin/checkout.c                            | 133 +++++++++++++-----\n cache.h                                       |   7 +-\n entry.c                                       |  26 ++++\n read-cache.c                                  |   8 +-\n split-index.c                                 |   2 +-\n t/t2025-checkout-no-overlay.sh                |  57 ++++++++\n ...-worktree-add.sh => t2400-worktree-add.sh} |   0\n ...ktree-prune.sh => t2401-worktree-prune.sh} |   0\n ...orktree-list.sh => t2402-worktree-list.sh} |   0\n ...orktree-move.sh => t2403-worktree-move.sh} |   0\n ...ree-config.sh => t2404-worktree-config.sh} |   0\n t/t9902-completion.sh                         |   1 +\n unpack-trees.c                                |  21 +--\n 15 files changed, 213 insertions(+), 59 deletions(-)\n create mode 100755 t/t2025-checkout-no-overlay.sh\n rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n rename t/{t2028-worktree-move.sh => t2403-worktree-move.sh} (100%)\n rename t/{t2029-worktree-config.sh => t2404-worktree-config.sh} (100%)\n\n-- \n2.20.1.153.gd81d796ee0\n\n     \n"},{"id":"366372","messageId":"20190108215225.3077-3-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20190108215225.3077-1-t.gummerer@gmail.com","subject":"[PATCH v3 2/8] entry: factor out unlink_entry function","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:19Z","receivedAt":"2019-01-08T21:52:38Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Factor out the 'unlink_entry()' function from unpack-trees.c to\nentry.c.  It will be used in other places as well in subsequent\nsteps.\n\nAs it's no longer a static function, also move the documentation to\nthe header file to make it more discoverable.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n cache.h        |  5 +++++\n entry.c        | 15 +++++++++++++++\n unpack-trees.c | 19 -------------------\n 3 files changed, 20 insertions(+), 19 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex ca36b44ee0..c1c953e810 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1542,6 +1542,11 @@ struct checkout {\n extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);\n extern void enable_delayed_checkout(struct checkout *state);\n extern int finish_delayed_checkout(struct checkout *state);\n+/*\n+ * Unlink the last component and schedule the leading directories for\n+ * removal, such that empty directories get removed.\n+ */\n+extern void unlink_entry(const struct cache_entry *ce);\n \n struct cache_def {\n \tstruct strbuf path;\ndiff --git a/entry.c b/entry.c\nindex 0a3c451f5f..b9eef57117 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -508,3 +508,18 @@ int checkout_entry(struct cache_entry *ce,\n \tcreate_directories(path.buf, path.len, state);\n \treturn write_entry(ce, path.buf, state, 0);\n }\n+\n+void unlink_entry(const struct cache_entry *ce)\n+{\n+\tconst struct submodule *sub = submodule_from_ce(ce);\n+\tif (sub) {\n+\t\t/* state.force is set at the caller. */\n+\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n+\t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n+\t}\n+\tif (!check_leading_path(ce->name, ce_namelen(ce)))\n+\t\treturn;\n+\tif (remove_or_warn(ce->ce_mode, ce->name))\n+\t\treturn;\n+\tschedule_dir_for_removal(ce->name, ce_namelen(ce));\n+}\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex 7570df481b..e8d1a6ac50 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -300,25 +300,6 @@ static void load_gitmodules_file(struct index_state *index,\n \t}\n }\n \n-/*\n- * Unlink the last component and schedule the leading directories for\n- * removal, such that empty directories get removed.\n- */\n-static void unlink_entry(const struct cache_entry *ce)\n-{\n-\tconst struct submodule *sub = submodule_from_ce(ce);\n-\tif (sub) {\n-\t\t/* state.force is set at the caller. */\n-\t\tsubmodule_move_head(ce->name, \"HEAD\", NULL,\n-\t\t\t\t    SUBMODULE_MOVE_HEAD_FORCE);\n-\t}\n-\tif (!check_leading_path(ce->name, ce_namelen(ce)))\n-\t\treturn;\n-\tif (remove_or_warn(ce->ce_mode, ce->name))\n-\t\treturn;\n-\tschedule_dir_for_removal(ce->name, ce_namelen(ce));\n-}\n-\n static struct progress *get_progress(struct unpack_trees_options *o)\n {\n \tunsigned cnt = 0, total = 0;\n-- \n2.20.1.153.gd81d796ee0\n\n"},{"id":"366373","messageId":"20190108215225.3077-2-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20190108215225.3077-1-t.gummerer@gmail.com","subject":"[PATCH v3 1/8] move worktree tests to t24*","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:18Z","receivedAt":"2019-01-08T21:52:39Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"The 'git worktree' command used to be just another mode in 'git\ncheckout', namely 'git checkout --to'.  When the tests for the latter\nwere retrofitted for the former, the test name was adjusted, but the\ntest number was kept, even though the test is testing a different\ncommand now.  t/README states: \"Second digit tells the particular\ncommand we are testing.\", so 'git worktree' should have a separate\nnumber just for itself.\n\nMove the worktree tests to t24* to adhere to that guideline. We're\ngoing to make use of the free'd up numbers in a subsequent commit.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n t/{t2025-worktree-add.sh => t2400-worktree-add.sh}       | 0\n t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh}   | 0\n t/{t2027-worktree-list.sh => t2402-worktree-list.sh}     | 0\n t/{t2028-worktree-move.sh => t2403-worktree-move.sh}     | 0\n t/{t2029-worktree-config.sh => t2404-worktree-config.sh} | 0\n 5 files changed, 0 insertions(+), 0 deletions(-)\n rename t/{t2025-worktree-add.sh => t2400-worktree-add.sh} (100%)\n rename t/{t2026-worktree-prune.sh => t2401-worktree-prune.sh} (100%)\n rename t/{t2027-worktree-list.sh => t2402-worktree-list.sh} (100%)\n rename t/{t2028-worktree-move.sh => t2403-worktree-move.sh} (100%)\n rename t/{t2029-worktree-config.sh => t2404-worktree-config.sh} (100%)\n\ndiff --git a/t/t2025-worktree-add.sh b/t/t2400-worktree-add.sh\nsimilarity index 100%\nrename from t/t2025-worktree-add.sh\nrename to t/t2400-worktree-add.sh\ndiff --git a/t/t2026-worktree-prune.sh b/t/t2401-worktree-prune.sh\nsimilarity index 100%\nrename from t/t2026-worktree-prune.sh\nrename to t/t2401-worktree-prune.sh\ndiff --git a/t/t2027-worktree-list.sh b/t/t2402-worktree-list.sh\nsimilarity index 100%\nrename from t/t2027-worktree-list.sh\nrename to t/t2402-worktree-list.sh\ndiff --git a/t/t2028-worktree-move.sh b/t/t2403-worktree-move.sh\nsimilarity index 100%\nrename from t/t2028-worktree-move.sh\nrename to t/t2403-worktree-move.sh\ndiff --git a/t/t2029-worktree-config.sh b/t/t2404-worktree-config.sh\nsimilarity index 100%\nrename from t/t2029-worktree-config.sh\nrename to t/t2404-worktree-config.sh\n-- \n2.20.1.153.gd81d796ee0\n\n"},{"id":"366374","messageId":"20190108215225.3077-5-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20190108215225.3077-1-t.gummerer@gmail.com","subject":"[PATCH v3 4/8] read-cache: add invalidate parameter to remove_marked_cache_entries","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:21Z","receivedAt":"2019-01-08T21:52:42Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"When marking cache entries for removal, and later removing them all at\nonce using 'remove_marked_cache_entries()', cache entries currently\nhave to be invalidated manually in the cache tree and in the untracked\ncache.\n\nAdd an invalidate flag to the function.  With the flag set, the\nfunction will take care of invalidating the path in the cache tree and\nin the untracked cache.\n\nNote that the current callsites already do the invalidation properly\nin other places, so we're just passing 0 from there to keep the status\nquo.\n\nThis will be useful in a subsequent commit.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n cache.h        | 2 +-\n read-cache.c   | 8 +++++++-\n split-index.c  | 2 +-\n unpack-trees.c | 2 +-\n 4 files changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex c1c953e810..1deee48f5b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -751,7 +751,7 @@ extern void rename_index_entry_at(struct index_state *, int pos, const char *new\n /* Remove entry, return true if there are more entries to go. */\n extern int remove_index_entry_at(struct index_state *, int pos);\n \n-extern void remove_marked_cache_entries(struct index_state *istate);\n+extern void remove_marked_cache_entries(struct index_state *istate, int invalidate);\n extern int remove_file_from_index(struct index_state *, const char *path);\n #define ADD_CACHE_VERBOSE 1\n #define ADD_CACHE_PRETEND 2\ndiff --git a/read-cache.c b/read-cache.c\nindex bd45dc3e24..978d43f676 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -590,13 +590,19 @@ int remove_index_entry_at(struct index_state *istate, int pos)\n  * CE_REMOVE is set in ce_flags.  This is much more effective than\n  * calling remove_index_entry_at() for each entry to be removed.\n  */\n-void remove_marked_cache_entries(struct index_state *istate)\n+void remove_marked_cache_entries(struct index_state *istate, int invalidate)\n {\n \tstruct cache_entry **ce_array = istate->cache;\n \tunsigned int i, j;\n \n \tfor (i = j = 0; i < istate->cache_nr; i++) {\n \t\tif (ce_array[i]->ce_flags & CE_REMOVE) {\n+\t\t\tif (invalidate) {\n+\t\t\t\tcache_tree_invalidate_path(istate,\n+\t\t\t\t\t\t\t   ce_array[i]->name);\n+\t\t\t\tuntracked_cache_remove_from_index(istate,\n+\t\t\t\t\t\t\t\t  ce_array[i]->name);\n+\t\t\t}\n \t\t\tremove_name_hash(istate, ce_array[i]);\n \t\t\tsave_or_free_index_entry(istate, ce_array[i]);\n \t\t}\ndiff --git a/split-index.c b/split-index.c\nindex 5820412dc5..8aebc3661b 100644\n--- a/split-index.c\n+++ b/split-index.c\n@@ -162,7 +162,7 @@ void merge_base_index(struct index_state *istate)\n \tewah_each_bit(si->replace_bitmap, replace_entry, istate);\n \tewah_each_bit(si->delete_bitmap, mark_entry_for_delete, istate);\n \tif (si->nr_deletions)\n-\t\tremove_marked_cache_entries(istate);\n+\t\tremove_marked_cache_entries(istate, 0);\n \n \tfor (i = si->nr_replacements; i < si->saved_cache_nr; i++) {\n \t\tif (!ce_namelen(si->saved_cache[i]))\ndiff --git a/unpack-trees.c b/unpack-trees.c\nindex e8d1a6ac50..8e6afa924d 100644\n--- a/unpack-trees.c\n+++ b/unpack-trees.c\n@@ -392,7 +392,7 @@ static int check_updates(struct unpack_trees_options *o)\n \t\t\t\tunlink_entry(ce);\n \t\t}\n \t}\n-\tremove_marked_cache_entries(index);\n+\tremove_marked_cache_entries(index, 0);\n \tremove_scheduled_dirs();\n \n \tif (should_update_submodules() && o->update && !o->dry_run)\n-- \n2.20.1.153.gd81d796ee0\n\n"},{"id":"366375","messageId":"20190108215225.3077-4-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20190108215225.3077-1-t.gummerer@gmail.com","subject":"[PATCH v3 3/8] entry: support CE_WT_REMOVE flag in checkout_entry","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:20Z","receivedAt":"2019-01-08T21:52:43Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"'checkout_entry()' currently only supports creating new entries in the\nworking tree, but not deleting them.  Add the ability to remove\nentries at the same time if the entry is marked with the CE_WT_REMOVE\nflag.\n\nCurrently this doesn't have any effect, as the CE_WT_REMOVE flag is\nonly used in unpack-tree, however we will make use of this in a\nsubsequent step in the series.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n entry.c | 11 +++++++++++\n 1 file changed, 11 insertions(+)\n\ndiff --git a/entry.c b/entry.c\nindex b9eef57117..3d3701e7ae 100644\n--- a/entry.c\n+++ b/entry.c\n@@ -441,6 +441,17 @@ int checkout_entry(struct cache_entry *ce,\n \tstatic struct strbuf path = STRBUF_INIT;\n \tstruct stat st;\n \n+\tif (ce->ce_flags & CE_WT_REMOVE) {\n+\t\tif (topath)\n+\t\t\t/*\n+\t\t\t * No content and thus no path to create, so we have\n+\t\t\t * no pathname to return.\n+\t\t\t */\n+\t\t\tBUG(\"Can't remove entry to a path\");\n+\t\tunlink_entry(ce);\n+\t\treturn 0;\n+\t}\n+\n \tif (topath)\n \t\treturn write_entry(ce, topath, state, 1);\n \n-- \n2.20.1.153.gd81d796ee0\n\n"},{"id":"366376","messageId":"20190108215225.3077-6-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20190108215225.3077-1-t.gummerer@gmail.com","subject":"[PATCH v3 5/8] checkout: clarify comment","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:22Z","receivedAt":"2019-01-08T21:52:45Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"The key point for the if statement is that read_tree_some did not\nupdate the entry, because either it doesn't exist in tree-ish or\ndoesn't match the pathspec.  Clarify that.\n\nSuggested-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n builtin/checkout.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex acdafc6e4c..cb166b2e07 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -304,10 +304,10 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\tcontinue;\n \t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n \t\t\t/*\n-\t\t\t * \"git checkout tree-ish -- path\", but this entry\n-\t\t\t * is in the original index; it will not be checked\n-\t\t\t * out to the working tree and it does not matter\n-\t\t\t * if pathspec matched this entry.  We will not do\n+\t\t\t * \"git checkout tree-ish -- path\" and this entry\n+\t\t\t * is in the original index, but is not in tree-ish\n+\t\t\t * or does not match the pathspec; it will not be\n+\t\t\t * checked out to the working tree.  We will not do\n \t\t\t * anything to this entry at all.\n \t\t\t */\n \t\t\tcontinue;\n-- \n2.20.1.153.gd81d796ee0\n\n"},{"id":"366377","messageId":"20190108215225.3077-7-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20190108215225.3077-1-t.gummerer@gmail.com","subject":"[PATCH v3 6/8] checkout: factor out mark_cache_entry_for_checkout function","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:23Z","receivedAt":"2019-01-08T21:52:46Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Factor out the code that marks a cache entry as matched for checkout\ninto a separate function.  We are going to introduce a new mode in\n'git checkout' in a subsequent commit, that is going to have a\nslightly different logic.  This would make this code unnecessarily\ncomplex.\n\nMoving that complexity into separate functions will make the code in\nthe subsequent step easier to follow.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n builtin/checkout.c | 67 +++++++++++++++++++++++++---------------------\n 1 file changed, 36 insertions(+), 31 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex cb166b2e07..32c4b7f897 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -247,6 +247,40 @@ static int checkout_merged(int pos, const struct checkout *state)\n \treturn status;\n }\n \n+static void mark_ce_for_checkout(struct cache_entry *ce,\n+\t\t\t\t char *ps_matched,\n+\t\t\t\t const struct checkout_opts *opts)\n+{\n+\tce->ce_flags &= ~CE_MATCHED;\n+\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n+\t\treturn;\n+\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n+\t\t/*\n+\t\t * \"git checkout tree-ish -- path\", but this entry\n+\t\t * is in the original index but is not in tree-ish\n+\t\t * or does not match the pathspec; it will not be\n+\t\t * checked out to the working tree.  We will not do\n+\t\t * anything to this entry at all.\n+\t\t */\n+\t\treturn;\n+\t/*\n+\t * Either this entry came from the tree-ish we are\n+\t * checking the paths out of, or we are checking out\n+\t * of the index.\n+\t *\n+\t * If it comes from the tree-ish, we already know it\n+\t * matches the pathspec and could just stamp\n+\t * CE_MATCHED to it from update_some(). But we still\n+\t * need ps_matched and read_tree_recursive (and\n+\t * eventually tree_entry_interesting) cannot fill\n+\t * ps_matched yet. Once it can, we can avoid calling\n+\t * match_pathspec() for _all_ entries when\n+\t * opts->source_tree != NULL.\n+\t */\n+\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))\n+\t\tce->ce_flags |= CE_MATCHED;\n+}\n+\n static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t  const char *revision)\n {\n@@ -297,37 +331,8 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t * Make sure all pathspecs participated in locating the paths\n \t * to be checked out.\n \t */\n-\tfor (pos = 0; pos < active_nr; pos++) {\n-\t\tstruct cache_entry *ce = active_cache[pos];\n-\t\tce->ce_flags &= ~CE_MATCHED;\n-\t\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n-\t\t\tcontinue;\n-\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n-\t\t\t/*\n-\t\t\t * \"git checkout tree-ish -- path\" and this entry\n-\t\t\t * is in the original index, but is not in tree-ish\n-\t\t\t * or does not match the pathspec; it will not be\n-\t\t\t * checked out to the working tree.  We will not do\n-\t\t\t * anything to this entry at all.\n-\t\t\t */\n-\t\t\tcontinue;\n-\t\t/*\n-\t\t * Either this entry came from the tree-ish we are\n-\t\t * checking the paths out of, or we are checking out\n-\t\t * of the index.\n-\t\t *\n-\t\t * If it comes from the tree-ish, we already know it\n-\t\t * matches the pathspec and could just stamp\n-\t\t * CE_MATCHED to it from update_some(). But we still\n-\t\t * need ps_matched and read_tree_recursive (and\n-\t\t * eventually tree_entry_interesting) cannot fill\n-\t\t * ps_matched yet. Once it can, we can avoid calling\n-\t\t * match_pathspec() for _all_ entries when\n-\t\t * opts->source_tree != NULL.\n-\t\t */\n-\t\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched))\n-\t\t\tce->ce_flags |= CE_MATCHED;\n-\t}\n+\tfor (pos = 0; pos < active_nr; pos++)\n+\t\tmark_ce_for_checkout(active_cache[pos], ps_matched, opts);\n \n \tif (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {\n \t\tfree(ps_matched);\n-- \n2.20.1.153.gd81d796ee0\n\n"},{"id":"366378","messageId":"20190108215225.3077-8-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20190108215225.3077-1-t.gummerer@gmail.com","subject":"[PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:24Z","receivedAt":"2019-01-08T21:52:48Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"Currently 'git checkout' is defined as an overlay operation, which\nmeans that if in 'git checkout <tree-ish> -- [<pathspec>]' we have an\nentry in the index that matches <pathspec>, but that doesn't exist in\n<tree-ish>, that entry will not be removed from the index or the\nworking tree.\n\nIntroduce a new --{,no-}overlay option, which allows using 'git\ncheckout' in non-overlay mode, thus removing files from the working\ntree if they do not exist in <tree-ish> but match <pathspec>.\n\nNote that 'git checkout -p <tree-ish> -- [<pathspec>]' already works\nthis way, so no changes are needed for the patch mode.  We disallow\n'git checkout --overlay -p' to avoid confusing users who would expect\nto be able to force overlay mode in 'git checkout -p' this way.\n\nUntracked files are not affected by this change, so 'git checkout\n--no-overlay HEAD -- untracked' will not remove untracked from the\nworking tree.  This is so e.g. 'git checkout --no-overlay HEAD -- dir/'\ndoesn't delete all untracked files in dir/, but rather just resets the\nstate of files that are known to git.\n\nSuggested-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/git-checkout.txt | 10 ++++++\n builtin/checkout.c             | 66 +++++++++++++++++++++++++++++-----\n t/t2025-checkout-no-overlay.sh | 47 ++++++++++++++++++++++++\n t/t9902-completion.sh          |  1 +\n 4 files changed, 116 insertions(+), 8 deletions(-)\n create mode 100755 t/t2025-checkout-no-overlay.sh\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 801de2f764..24e52b01e1 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -260,6 +260,9 @@ the conflicted merge in the specified paths.\n This means that you can use `git checkout -p` to selectively discard\n edits from your current working tree. See the ``Interactive Mode''\n section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n++\n+Note that this option uses the no overlay mode by default (see also\n+`--[no-]overlay`), and currently doesn't support overlay mode.\n \n --ignore-other-worktrees::\n \t`git checkout` refuses when the wanted ref is already checked\n@@ -276,6 +279,13 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.\n \tJust like linkgit:git-submodule[1], this will detach the\n \tsubmodules HEAD.\n \n+--[no-]overlay::\n+\tIn the default overlay mode, `git checkout` never\n+\tremoves files from the index or the working tree.  When\n+\tspecifying `--no-overlay`, files that appear in the index and\n+\tworking tree, but not in <tree-ish> are removed, to make them\n+\tmatch <tree-ish> exactly.\n+\n <branch>::\n \tBranch to checkout; if it refers to a branch (i.e., a name that,\n \twhen prepended with \"refs/heads/\", is a valid ref), then that\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 32c4b7f897..0c5fe948ef 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -44,6 +44,7 @@ struct checkout_opts {\n \tint ignore_skipworktree;\n \tint ignore_other_worktrees;\n \tint show_progress;\n+\tint overlay_mode;\n \t/*\n \t * If new checkout options are added, skip_merge_working_tree\n \t * should be updated accordingly.\n@@ -132,7 +133,8 @@ static int skip_same_name(const struct cache_entry *ce, int pos)\n \treturn pos;\n }\n \n-static int check_stage(int stage, const struct cache_entry *ce, int pos)\n+static int check_stage(int stage, const struct cache_entry *ce, int pos,\n+\t\t       int overlay_mode)\n {\n \twhile (pos < active_nr &&\n \t       !strcmp(active_cache[pos]->name, ce->name)) {\n@@ -140,6 +142,8 @@ static int check_stage(int stage, const struct cache_entry *ce, int pos)\n \t\t\treturn 0;\n \t\tpos++;\n \t}\n+\tif (!overlay_mode)\n+\t\treturn 0;\n \tif (stage == 2)\n \t\treturn error(_(\"path '%s' does not have our version\"), ce->name);\n \telse\n@@ -165,7 +169,7 @@ static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)\n }\n \n static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n-\t\t\t  const struct checkout *state)\n+\t\t\t  const struct checkout *state, int overlay_mode)\n {\n \twhile (pos < active_nr &&\n \t       !strcmp(active_cache[pos]->name, ce->name)) {\n@@ -173,6 +177,10 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,\n \t\t\treturn checkout_entry(active_cache[pos], state, NULL);\n \t\tpos++;\n \t}\n+\tif (!overlay_mode) {\n+\t\tunlink_entry(ce);\n+\t\treturn 0;\n+\t}\n \tif (stage == 2)\n \t\treturn error(_(\"path '%s' does not have our version\"), ce->name);\n \telse\n@@ -247,9 +255,9 @@ static int checkout_merged(int pos, const struct checkout *state)\n \treturn status;\n }\n \n-static void mark_ce_for_checkout(struct cache_entry *ce,\n-\t\t\t\t char *ps_matched,\n-\t\t\t\t const struct checkout_opts *opts)\n+static void mark_ce_for_checkout_overlay(struct cache_entry *ce,\n+\t\t\t\t\t char *ps_matched,\n+\t\t\t\t\t const struct checkout_opts *opts)\n {\n \tce->ce_flags &= ~CE_MATCHED;\n \tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n@@ -281,6 +289,25 @@ static void mark_ce_for_checkout(struct cache_entry *ce,\n \t\tce->ce_flags |= CE_MATCHED;\n }\n \n+static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,\n+\t\t\t\t\t    char *ps_matched,\n+\t\t\t\t\t    const struct checkout_opts *opts)\n+{\n+\tce->ce_flags &= ~CE_MATCHED;\n+\tif (!opts->ignore_skipworktree && ce_skip_worktree(ce))\n+\t\treturn;\n+\tif (ce_path_match(&the_index, ce, &opts->pathspec, ps_matched)) {\n+\t\tce->ce_flags |= CE_MATCHED;\n+\t\tif (opts->source_tree && !(ce->ce_flags & CE_UPDATE))\n+\t\t\t/*\n+\t\t\t * In overlay mode, but the path is not in\n+\t\t\t * tree-ish, which means we should remove it\n+\t\t\t * from the index and the working tree.\n+\t\t\t */\n+\t\t\tce->ce_flags |= CE_REMOVE | CE_WT_REMOVE;\n+\t}\n+}\n+\n static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t  const char *revision)\n {\n@@ -332,7 +359,14 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t * to be checked out.\n \t */\n \tfor (pos = 0; pos < active_nr; pos++)\n-\t\tmark_ce_for_checkout(active_cache[pos], ps_matched, opts);\n+\t\tif (opts->overlay_mode)\n+\t\t\tmark_ce_for_checkout_overlay(active_cache[pos],\n+\t\t\t\t\t\t     ps_matched,\n+\t\t\t\t\t\t     opts);\n+\t\telse\n+\t\t\tmark_ce_for_checkout_no_overlay(active_cache[pos],\n+\t\t\t\t\t\t\tps_matched,\n+\t\t\t\t\t\t\topts);\n \n \tif (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {\n \t\tfree(ps_matched);\n@@ -353,7 +387,7 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\tif (opts->force) {\n \t\t\t\twarning(_(\"path '%s' is unmerged\"), ce->name);\n \t\t\t} else if (opts->writeout_stage) {\n-\t\t\t\terrs |= check_stage(opts->writeout_stage, ce, pos);\n+\t\t\t\terrs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode);\n \t\t\t} else if (opts->merge) {\n \t\t\t\terrs |= check_stages((1<<2) | (1<<3), ce, pos);\n \t\t\t} else {\n@@ -380,12 +414,14 @@ static int checkout_paths(const struct checkout_opts *opts,\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (opts->writeout_stage)\n-\t\t\t\terrs |= checkout_stage(opts->writeout_stage, ce, pos, &state);\n+\t\t\t\terrs |= checkout_stage(opts->writeout_stage, ce, pos, &state, opts->overlay_mode);\n \t\t\telse if (opts->merge)\n \t\t\t\terrs |= checkout_merged(pos, &state);\n \t\t\tpos = skip_same_name(ce, pos) - 1;\n \t\t}\n \t}\n+\tremove_marked_cache_entries(&the_index, 1);\n+\tremove_scheduled_dirs();\n \terrs |= finish_delayed_checkout(&state);\n \n \tif (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))\n@@ -547,6 +583,11 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,\n \t * opts->show_progress only impacts output so doesn't require a merge\n \t */\n \n+\t/*\n+\t * opts->overlay_mode cannot be used with switching branches so is\n+\t * not tested here\n+\t */\n+\n \t/*\n \t * If we aren't creating a new branch any changes or updates will\n \t * happen in the existing branch.  Since that could only be updating\n@@ -1183,6 +1224,10 @@ static int checkout_branch(struct checkout_opts *opts,\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n \t\t    \"--patch\");\n \n+\tif (!opts->overlay_mode)\n+\t\tdie(_(\"'%s' cannot be used with switching branches\"),\n+\t\t    \"--no-overlay\");\n+\n \tif (opts->writeout_stage)\n \t\tdie(_(\"'%s' cannot be used with switching branches\"),\n \t\t    \"--ours/--theirs\");\n@@ -1271,6 +1316,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\t\t    \"checkout\", \"control recursive updating of submodules\",\n \t\t\t    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },\n \t\tOPT_BOOL(0, \"progress\", &opts.show_progress, N_(\"force progress reporting\")),\n+\t\tOPT_BOOL(0, \"overlay\", &opts.overlay_mode, N_(\"use overlay mode (default)\")),\n \t\tOPT_END(),\n \t};\n \n@@ -1279,6 +1325,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \topts.overwrite_ignore = 1;\n \topts.prefix = prefix;\n \topts.show_progress = -1;\n+\topts.overlay_mode = -1;\n \n \tgit_config(git_checkout_config, &opts);\n \n@@ -1302,6 +1349,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tif ((!!opts.new_branch + !!opts.new_branch_force + !!opts.new_orphan_branch) > 1)\n \t\tdie(_(\"-b, -B and --orphan are mutually exclusive\"));\n \n+\tif (opts.overlay_mode == 1 && opts.patch_mode)\n+\t\tdie(_(\"-p and --overlay are mutually exclusive\"));\n+\n \t/*\n \t * From here on, new_branch will contain the branch to be checked out,\n \t * and new_branch_force and new_orphan_branch will tell us which one of\ndiff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh\nnew file mode 100755\nindex 0000000000..76330cb5ab\n--- /dev/null\n+++ b/t/t2025-checkout-no-overlay.sh\n@@ -0,0 +1,47 @@\n+#!/bin/sh\n+\n+test_description='checkout --no-overlay <tree-ish> -- <pathspec>'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\tgit commit --allow-empty -m \"initial\"\n+'\n+\n+test_expect_success 'checkout --no-overlay deletes files not in <tree-ish>' '\n+\t>file &&\n+\tmkdir dir &&\n+\t>dir/file1 &&\n+\tgit add file dir/file1 &&\n+\tgit checkout --no-overlay HEAD -- file &&\n+\ttest_path_is_missing file &&\n+\ttest_path_is_file dir/file1\n+'\n+\n+test_expect_success 'checkout --no-overlay removing last file from directory' '\n+\tgit checkout --no-overlay HEAD -- dir/file1 &&\n+\ttest_path_is_missing dir\n+'\n+\n+test_expect_success 'checkout -p --overlay is disallowed' '\n+\ttest_must_fail git checkout -p --overlay HEAD 2>actual &&\n+\ttest_i18ngrep \"fatal: -p and --overlay are mutually exclusive\" actual\n+'\n+\n+test_expect_success '--no-overlay --theirs with D/F conflict deletes file' '\n+\ttest_commit file1 file1 &&\n+\ttest_commit file2 file2 &&\n+\tgit rm --cached file1 &&\n+\techo 1234 >file1 &&\n+\tF1=$(git rev-parse HEAD:file1) &&\n+\tF2=$(git rev-parse HEAD:file2) &&\n+\t{\n+\t\techo \"100644 $F1 1\tfile1\" &&\n+\t\techo \"100644 $F2 2\tfile1\"\n+\t} | git update-index --index-info &&\n+\ttest_path_is_file file1 &&\n+\tgit checkout --theirs --no-overlay -- file1 &&\n+\ttest_path_is_missing file1\n+'\n+\n+test_done\ndiff --git a/t/t9902-completion.sh b/t/t9902-completion.sh\nindex d01ad8eb25..5758fffa0d 100755\n--- a/t/t9902-completion.sh\n+++ b/t/t9902-completion.sh\n@@ -1436,6 +1436,7 @@ test_expect_success 'double dash \"git checkout\"' '\n \t--progress Z\n \t--no-quiet Z\n \t--no-... Z\n+\t--overlay Z\n \tEOF\n '\n \n-- \n2.20.1.153.gd81d796ee0\n\n"},{"id":"366379","messageId":"20190108215225.3077-9-t.gummerer@gmail.com","threadId":"49988","inReplyTo":"20190108215225.3077-1-t.gummerer@gmail.com","subject":"[PATCH v3 8/8] checkout: introduce checkout.overlayMode config","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-08T21:52:25Z","receivedAt":"2019-01-08T21:52:48Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"In the previous patch we introduced a new no-overlay mode for git\ncheckout.  Some users (such as the author of this commit) may want to\nhave this mode turned on by default as it matches their mental model\nmore closely.  Make that possible by introducing a new config option\nto that extend.\n\nSigned-off-by: Thomas Gummerer <t.gummerer@gmail.com>\n---\n Documentation/config/checkout.txt |  7 +++++++\n builtin/checkout.c                |  8 +++++++-\n t/t2025-checkout-no-overlay.sh    | 10 ++++++++++\n 3 files changed, 24 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/config/checkout.txt b/Documentation/config/checkout.txt\nindex c4118fa196..73380a8d86 100644\n--- a/Documentation/config/checkout.txt\n+++ b/Documentation/config/checkout.txt\n@@ -21,3 +21,10 @@ checkout.optimizeNewBranch::\n \twill not update the skip-worktree bit in the index nor add/remove\n \tfiles in the working directory to reflect the current sparse checkout\n \tsettings nor will it show the local changes.\n+\n+checkout.overlayMode::\n+\tIn the default overlay mode, `git checkout` never\n+\tremoves files from the index or the working tree.  When\n+\tsetting `checkout.overlayMode` to false, files that appear in\n+\tthe index and working tree, but not in <tree-ish> are removed,\n+\tto make them match <tree-ish> exactly.\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 0c5fe948ef..b5dfc45736 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -1019,13 +1019,19 @@ static int switch_branches(const struct checkout_opts *opts,\n \n static int git_checkout_config(const char *var, const char *value, void *cb)\n {\n+\tstruct checkout_opts *opts = cb;\n+\n \tif (!strcmp(var, \"checkout.optimizenewbranch\")) {\n \t\tcheckout_optimize_new_branch = git_config_bool(var, value);\n \t\treturn 0;\n \t}\n \n+\tif (!strcmp(var, \"checkout.overlaymode\")) {\n+\t\topts->overlay_mode = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \tif (!strcmp(var, \"diff.ignoresubmodules\")) {\n-\t\tstruct checkout_opts *opts = cb;\n \t\thandle_ignore_submodules_arg(&opts->diff_options, value);\n \t\treturn 0;\n \t}\ndiff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh\nindex 76330cb5ab..a4912e35cb 100755\n--- a/t/t2025-checkout-no-overlay.sh\n+++ b/t/t2025-checkout-no-overlay.sh\n@@ -44,4 +44,14 @@ test_expect_success '--no-overlay --theirs with D/F conflict deletes file' '\n \ttest_path_is_missing file1\n '\n \n+test_expect_success 'checkout with checkout.overlayMode=false deletes files not in <tree-ish>' '\n+\t>file &&\n+\tmkdir dir &&\n+\t>dir/file1 &&\n+\tgit add file dir/file1 &&\n+\tgit -c checkout.overlayMode=false checkout HEAD -- file &&\n+\ttest_path_is_missing file &&\n+\ttest_path_is_file dir/file1\n+'\n+\n test_done\n-- \n2.20.1.153.gd81d796ee0\n\n"},{"id":"367395","messageId":"20190122235313.GA199923@google.com","threadId":"49988","inReplyTo":"20190108215225.3077-8-t.gummerer@gmail.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2019-01-22T23:53:13Z","receivedAt":"2019-01-22T23:53:18Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nThomas Gummerer wrote:\n\n> Currently 'git checkout' is defined as an overlay operation, which\n> means that if in 'git checkout <tree-ish> -- [<pathspec>]' we have an\n> entry in the index that matches <pathspec>, but that doesn't exist in\n> <tree-ish>, that entry will not be removed from the index or the\n> working tree.\n>\n> Introduce a new --{,no-}overlay option, which allows using 'git\n> checkout' in non-overlay mode, thus removing files from the working\n> tree if they do not exist in <tree-ish> but match <pathspec>.\n\nThis patch just hit my workstation.  Some initial thoughts:\n\nI had no idea what --overlay would mean and am still not clear on it.\nIs this analogous to \"git add --ignore-removal\"?  If so, can we just\ncall it --ignore-removal?\n\nThank you thank you thank you for working on this.  I run into this\nall the time and am super excited about the \"default to\n--no-ignore-removal\" future.\n\nI'm nervous about the config with no associated warning or plan for\nphasing it out.  It means that scripts using \"git checkout\" don't\nget a consistent behavior unless they explicitly pass this option,\nwhich didn't exist in older versions of Git --- in other words,\nscripts have no real good option.  Can we plan a transition to\nmaking --no-ignore-removal the default, in multiple steps?  For\nexample:\n\n 1. First introduce the commandline option, as in this series\n\n 2. Next, change the default to warn whenever the difference would\n    matter, printing a hint about how to configure to explicitly\n    request the old or new behavior.\n\n 3. After a release or two has passed so people get a chance\n    to update their scripts, flip the default.\n\n 4. Finally, remove the warning.\n\n 5. Warn whenver the difference would matter when a user has\n    requested the old behavior through config, in preparation\n    for removing the config.\n\n 6. Remove the config.\n\nSteps 5 and 6 are optional but might be nice.\n\nWhat do you think?\n\nThanks,\nJonathan\n"},{"id":"367450","messageId":"xmqqy37bb3ff.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"20190122235313.GA199923@google.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-23T19:05:08Z","receivedAt":"2019-01-23T19:05:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> I'm nervous about the config with no associated warning or plan for\n> phasing it out.\n\nThis was discussed long ago (in my panda-brain timescale) but my\nrecollection is to keep \"checkout\" default to the traditional\n\"overlay what was read from the tree on top of the current index\"\nbehaviour, while the new \"checkout-paths\" subcommand (split from the\n\"checkout\" subcommand to produce two subcommands, the other one\nbeing the \"checkout-branch\" subcommand) would default to the new \"no\noverlay\" behaviour.\n\nSo I am not sure if we even need a detailed transition plan.\n\nIf we were to make \"checkout\" pay attention to a local\nconfiguration, that is a different story, as scripts that have\nalways assumed the overlay behaviour will be broken by such a\nconfiguration variable.  But with the introduction of two new\nsubcommands in the picture to help interactive end users, I am not\nsure if it is even worth considering to allow \"checkout\" to change\nbehaviour based on a configuration.  Those who want no-overlay\nbehaviour can switch to checkout-paths and be done with it, while\nscripts can keep relying on the overlay behaviour, no?\n\n\n"},{"id":"367459","messageId":"20190123202156.GA11293@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"20190122235313.GA199923@google.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-23T20:21:56Z","receivedAt":"2019-01-23T20:22:02Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 01/22, Jonathan Nieder wrote:\n> Hi,\n> \n> Thomas Gummerer wrote:\n> \n> > Currently 'git checkout' is defined as an overlay operation, which\n> > means that if in 'git checkout <tree-ish> -- [<pathspec>]' we have an\n> > entry in the index that matches <pathspec>, but that doesn't exist in\n> > <tree-ish>, that entry will not be removed from the index or the\n> > working tree.\n> >\n> > Introduce a new --{,no-}overlay option, which allows using 'git\n> > checkout' in non-overlay mode, thus removing files from the working\n> > tree if they do not exist in <tree-ish> but match <pathspec>.\n> \n> This patch just hit my workstation.  Some initial thoughts:\n> \n> I had no idea what --overlay would mean and am still not clear on it.\n> Is this analogous to \"git add --ignore-removal\"?  If so, can we just\n> call it --ignore-removal?\n\nYes, it seems like they are very similar.  I'm happy to rename the\noption.  The topic seems to have made it to 'next' already, so I'll\nsubmit the patches on top, unless reverting the topic out of next and\nreplacing it is preferred?\n\n> Thank you thank you thank you for working on this.  I run into this\n> all the time and am super excited about the \"default to\n> --no-ignore-removal\" future.\n\n:)\n\n> I'm nervous about the config with no associated warning or plan for\n> phasing it out.  It means that scripts using \"git checkout\" don't\n> get a consistent behavior unless they explicitly pass this option,\n> which didn't exist in older versions of Git --- in other words,\n> scripts have no real good option.  Can we plan a transition to\n> making --no-ignore-removal the default, in multiple steps?  For\n> example:\n\nAs Junio mentioned, the plan was to just have this mode default when\nwe introduce the new checkout-paths command.\n\nAs checkout is a porcelain command, I had hoped it would be okay to\nalso have this as a configuration option, for the time before\n'checkout-paths' exists and while I'm getting used to actually typing\n'checkout-paths' instead of 'checkout'.  However I get that there may\nbe scripts that are using git checkout, and expect the previous\nbehaviour, so I'm also okay with dropping the config option for now.\n\nIf we still want to make this the default even after 'checkout-paths'\nexists, the plan you outline below sounds good to me, though maybe we\ncan make the \"flip the default\" step once we decide to release git\n3.0.\n\n>  1. First introduce the commandline option, as in this series\n> \n>  2. Next, change the default to warn whenever the difference would\n>     matter, printing a hint about how to configure to explicitly\n>     request the old or new behavior.\n> \n>  3. After a release or two has passed so people get a chance\n>     to update their scripts, flip the default.\n> \n>  4. Finally, remove the warning.\n> \n>  5. Warn whenver the difference would matter when a user has\n>     requested the old behavior through config, in preparation\n>     for removing the config.\n> \n>  6. Remove the config.\n> \n> Steps 5 and 6 are optional but might be nice.\n> \n> What do you think?\n> \n> Thanks,\n> Jonathan\n"},{"id":"367461","messageId":"20190123204721.GB34357@google.com","threadId":"49988","inReplyTo":"20190123202156.GA11293@hank.intra.tgummerer.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2019-01-23T20:47:21Z","receivedAt":"2019-01-23T20:47:25Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Thomas Gummerer wrote:\n> On 01/22, Jonathan Nieder wrote:\n\n>> I had no idea what --overlay would mean and am still not clear on it.\n>> Is this analogous to \"git add --ignore-removal\"?  If so, can we just\n>> call it --ignore-removal?\n>\n> Yes, it seems like they are very similar.  I'm happy to rename the\n> option.  The topic seems to have made it to 'next' already, so I'll\n> submit the patches on top, unless reverting the topic out of next and\n> replacing it is preferred?\n\nA patch on top sounds good.\n\n[...]\n>> I'm nervous about the config with no associated warning or plan for\n>> phasing it out.  It means that scripts using \"git checkout\" don't\n>> get a consistent behavior unless they explicitly pass this option,\n>> which didn't exist in older versions of Git --- in other words,\n>> scripts have no real good option.  Can we plan a transition to\n>> making --no-ignore-removal the default, in multiple steps?  For\n>> example:\n>\n> As Junio mentioned, the plan was to just have this mode default when\n> we introduce the new checkout-paths command.\n>\n> As checkout is a porcelain command, I had hoped it would be okay to\n> also have this as a configuration option, for the time before\n> 'checkout-paths' exists and while I'm getting used to actually typing\n> 'checkout-paths' instead of 'checkout'.  However I get that there may\n> be scripts that are using git checkout, and expect the previous\n> behaviour, so I'm also okay with dropping the config option for now.\n\nYes, if we have no plan for flipping the default later, then I would\nprefer to eliminate the config option.  Scripts very frequently use\nhuman-facing commands like \"git checkout\" when they want the command\nto produce (unparsable) friendly output to show to humans, and I don't\nthink we've provided a good alternative for that use case.\n\n> If we still want to make this the default even after 'checkout-paths'\n> exists, the plan you outline below sounds good to me, though maybe we\n> can make the \"flip the default\" step once we decide to release git\n> 3.0.\n\nI would really like this, so I might write a series for it.  Please\ndon't wait for me, though --- feel free to send any patches you're\nthinking about and we can work together or I can just appreciate your\nwork. ;-)\n\nSincerely,\nJonathan\n"},{"id":"367481","messageId":"xmqqzhrr9j52.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"20190123202156.GA11293@hank.intra.tgummerer.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-23T21:08:41Z","receivedAt":"2019-01-23T21:08:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Gummerer <t.gummerer@gmail.com> writes:\n\n>> I had no idea what --overlay would mean and am still not clear on it.\n>> Is this analogous to \"git add --ignore-removal\"?  If so, can we just\n>> call it --ignore-removal?\n>\n> Yes, it seems like they are very similar.\n\nHmm, I am not sure if the word \"removal\" makes sense in the context\nof \"checkout\", as \"removal\" is an _action_ just like \"checking out\"\nitself is, and not a _state_.  You'd check out a state out of a tree\nto the index and the working tree, so \"checking out absence of a\npath\" may make sense, though, as \"absence of a path\" is a state\nrecorded in that source tree object.\n\nThe word \"removal\" makes little sense in \"git add --ignore-removal\",\nbut it and \"git add --no-all\" outlived their usefulness already, so\nit may not be worth _fixing_ it.  But I am mildly opposed to spread\nthe earlier mistake to a new option.\n"},{"id":"367514","messageId":"20190124011244.GE34357@google.com","threadId":"49988","inReplyTo":"xmqqzhrr9j52.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2019-01-24T01:12:44Z","receivedAt":"2019-01-24T01:12:49Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Hi,\n\nJunio C Hamano wrote:\n> Thomas Gummerer <t.gummerer@gmail.com> writes:\n>> Jonathan Nieder wrote:\n\n>>> Is this analogous to \"git add --ignore-removal\"?  If so, can we just\n>>> call it --ignore-removal?\n>>\n>> Yes, it seems like they are very similar.\n>\n> Hmm, I am not sure if the word \"removal\" makes sense in the context\n> of \"checkout\", as \"removal\" is an _action_ just like \"checking out\"\n> itself is, and not a _state_.  You'd check out a state out of a tree\n> to the index and the working tree, so \"checking out absence of a\n> path\" may make sense, though, as \"absence of a path\" is a state\n> recorded in that source tree object.\n\nI find --ignore-removal fairly easy to understand, and I had no idea\nwhat --overlay would mean.\n\nI realize this is just one user's experience.  I'd be happy to do a\nlittle informal survey (e.g. taking the description from the manpage\nand asking people to name the option) if that's useful.\n\nSee also https://dl.acm.org/citation.cfm?id=32212 on this subject.\n\n> The word \"removal\" makes little sense in \"git add --ignore-removal\",\n> but it and \"git add --no-all\" outlived their usefulness already, so\n> it may not be worth _fixing_ it.  But I am mildly opposed to spread\n> the earlier mistake to a new option.\n\nI think that's a good place to end up: once we flip the default for\ncheckout, then --ignore-removal would be an obscure option in that\ncommand as well.  The consistency with \"git add\" is just a bonus.\n\nThanks,\nJonathan\n"},{"id":"367622","messageId":"20190124220236.GB11293@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"20190124011244.GE34357@google.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-24T22:02:36Z","receivedAt":"2019-01-24T22:02:42Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 01/23, Jonathan Nieder wrote:\n> Hi,\n> \n> Junio C Hamano wrote:\n> > Thomas Gummerer <t.gummerer@gmail.com> writes:\n> >> Jonathan Nieder wrote:\n> \n> >>> Is this analogous to \"git add --ignore-removal\"?  If so, can we just\n> >>> call it --ignore-removal?\n> >>\n> >> Yes, it seems like they are very similar.\n> >\n> > Hmm, I am not sure if the word \"removal\" makes sense in the context\n> > of \"checkout\", as \"removal\" is an _action_ just like \"checking out\"\n> > itself is, and not a _state_.  You'd check out a state out of a tree\n> > to the index and the working tree, so \"checking out absence of a\n> > path\" may make sense, though, as \"absence of a path\" is a state\n> > recorded in that source tree object.\n> \n> I find --ignore-removal fairly easy to understand, and I had no idea\n> what --overlay would mean.\n\nWhat do you think about --[no-]ignore-removed?  That would not be the same\nas we are using in 'git add' though, and the slight difference may be\nworse than a different option?  Though I suspect not too many people\nare using --ignore-removal in 'git add' in the first place.\n\n> I realize this is just one user's experience.  I'd be happy to do a\n> little informal survey (e.g. taking the description from the manpage\n> and asking people to name the option) if that's useful.\n\nSure, that sounds like an option if we can't come to an agreement\nhere.  What would such a survey look like?\n\n> See also https://dl.acm.org/citation.cfm?id=32212 on this subject.\n\nSorry I don't have access to this, and unfortunately not the time to\nread this either at the moment.\n"},{"id":"367623","messageId":"20190124220801.GC11293@hank.intra.tgummerer.com","threadId":"49988","inReplyTo":"20190123204721.GB34357@google.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Thomas Gummerer","fromEmail":"t.gummerer@gmail.com","sentAt":"2019-01-24T22:08:01Z","receivedAt":"2019-01-24T22:08:07Z","isPatch":true,"sender":{"key":"t.gummerer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/191004?v=4"},"body":"On 01/23, Jonathan Nieder wrote:\n> Thomas Gummerer wrote:\n> > On 01/22, Jonathan Nieder wrote:\n> \n> > As checkout is a porcelain command, I had hoped it would be okay to\n> > also have this as a configuration option, for the time before\n> > 'checkout-paths' exists and while I'm getting used to actually typing\n> > 'checkout-paths' instead of 'checkout'.  However I get that there may\n> > be scripts that are using git checkout, and expect the previous\n> > behaviour, so I'm also okay with dropping the config option for now.\n> \n> Yes, if we have no plan for flipping the default later, then I would\n> prefer to eliminate the config option.  Scripts very frequently use\n> human-facing commands like \"git checkout\" when they want the command\n> to produce (unparsable) friendly output to show to humans, and I don't\n> think we've provided a good alternative for that use case.\n\nOk, I'm happy to drop that for now, and possibly re-introduce that\nwith another series to start flipping the default.  I'll probably wait\nfor Duy's checkout-paths command first though, and possibly send a\nseries later.\n\nJunio, do you just want to revert the patch (1495ff7da5 (\"checkout:\nintroduce checkout.overlayMode config\", 2019-01-08)), or would you\nprefer me sending a patch for that?\n\n> > If we still want to make this the default even after 'checkout-paths'\n> > exists, the plan you outline below sounds good to me, though maybe we\n> > can make the \"flip the default\" step once we decide to release git\n> > 3.0.\n> \n> I would really like this, so I might write a series for it.  Please\n> don't wait for me, though --- feel free to send any patches you're\n> thinking about and we can work together or I can just appreciate your\n> work. ;-)\n> \n> Sincerely,\n> Jonathan\n"},{"id":"367626","messageId":"xmqq8sz9hd6e.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"20190124011244.GE34357@google.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-24T23:02:33Z","receivedAt":"2019-01-24T23:02:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> I find --ignore-removal fairly easy to understand, and I had no idea\n> what --overlay would mean.\n>\n> I realize this is just one user's experience.\n\nExactly.  My impression was the exact opposite from yours.\n\nThe phrase \"removal\" in the context of checkout does not click for\nme at all, and neither it does in the context of add, especially\ngiven that Git tracks states (i.e. snapshots), not changes.\n\n\n"},{"id":"367637","messageId":"20190125022649.GA540@google.com","threadId":"49988","inReplyTo":"xmqq8sz9hd6e.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2019-01-25T02:26:49Z","receivedAt":"2019-01-25T02:26:55Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Junio C Hamano wrote:\n> Jonathan Nieder <jrnieder@gmail.com> writes:\n\n>> I find --ignore-removal fairly easy to understand, and I had no idea\n>> what --overlay would mean.\n>>\n>> I realize this is just one user's experience.\n>\n> Exactly.  My impression was the exact opposite from yours.\n>\n> The phrase \"removal\" in the context of checkout does not click for\n> me at all, and neither it does in the context of add, especially\n> given that Git tracks states (i.e. snapshots), not changes.\n\nThanks.  What do you think of --skip-removals (or --skip-deletions)?\nThe idea is \"among the changes that you would be making to the\nworktree, skip any unlink() steps\".\n\nIf that seems sensible, we can use it for \"git checkout\" and,\noptionally, add it as a synonym for --ignore-removal to \"git add\" as\nwell.\n\nJonathan\n"},{"id":"367638","messageId":"CACsJy8Cn-kb6793TLHwszh5E79JeCLhUPjJsfKv0Yfujd_-_0A@mail.gmail.com","threadId":"49988","inReplyTo":"20190125022649.GA540@google.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-01-25T09:24:56Z","receivedAt":"2019-01-25T09:25:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Jan 25, 2019 at 9:26 AM Jonathan Nieder <jrnieder@gmail.com> wrote:\n>\n> Junio C Hamano wrote:\n> > Jonathan Nieder <jrnieder@gmail.com> writes:\n>\n> >> I find --ignore-removal fairly easy to understand, and I had no idea\n> >> what --overlay would mean.\n> >>\n> >> I realize this is just one user's experience.\n> >\n> > Exactly.  My impression was the exact opposite from yours.\n> >\n> > The phrase \"removal\" in the context of checkout does not click for\n> > me at all, and neither it does in the context of add, especially\n> > given that Git tracks states (i.e. snapshots), not changes.\n>\n> Thanks.  What do you think of --skip-removals (or --skip-deletions)?\n> The idea is \"among the changes that you would be making to the\n> worktree, skip any unlink() steps\".\n\nAnother option from rsync: --delete (and --no-delete of course)\n-- \nDuy\n"},{"id":"368213","messageId":"CACsJy8Bk=wbgzsE+Vo4w_u0E63PdUxxcvG-7e6Hq-8_jrmSErw@mail.gmail.com","threadId":"49988","inReplyTo":"CACsJy8AxUxYCO7bzb98EVvO5DU62ukZQNrF-sEktrdR9m6tfvg@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-01-31T05:54:50Z","receivedAt":"2019-01-31T05:55:19Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Dec 12, 2018 at 2:23 AM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Tue, Dec 11, 2018 at 7:12 AM Elijah Newren <newren@gmail.com> wrote:\n> >\n> > On Mon, Dec 10, 2018 at 7:13 PM Junio C Hamano <gitster@pobox.com> wrote:\n> > >\n> > > Duy Nguyen <pclouds@gmail.com> writes:\n> > >\n> > > > Elijah wanted another mode (and I agree) that modifies worktree but\n> > > > leaves the index alone. This is most useful (or least confusing) when\n> > > > used with <tree-ish> and would be default in restore-files. I'm not\n> > > > saying you have to implement it, but how do the new command line\n> > > > options are designed to make sense?\n> > >\n> > > I'd model it after \"git apply\", i.e.\n> > >\n> > >         git restore-files [--tree=<treeish>] <pathspec>\n> > >\n> > > would work only on the working tree files,\n> > >\n> > >         git restore-files --tree=<treeish> --cached <pathspec>\n> > >\n> > > would match the entries in the index that match pathspec to the\n> > > given treeish without touching the working tree, and\n> > >\n> > >         git restore-files --tree=<treeish> --index <pathspec>\n> > >\n> > > would be both.\n> > >\n> > > I have never been happy with the phraso, the (arbitrary) distinction\n> > > between --cached/--index we use, so in the very longer term (like,\n> > > introducing synonym at 3.0 boundary and deprecating older ones at\n> > > 4.0 boundary), it may not be a bad idea to rename \"--index\" to\n> > > \"--index-and-working-tree\" and \"--cached\" to \"--index-only\".\n> > >\n> > > But until that happens, it would be better to use these two\n> > > consistently.\n> >\n> > I agree that consistency is important, but trying to distinguish\n> > between \"--cached\" and \"--index\" is _extremely_ painful.  I still\n> > can't keep the distinction straight and have to look it up every time\n> > I want to use either.  I don't know how to possibly teach users the\n> > meaning.  Could we introduce synonyms earlier at least, and make the\n> > synonyms more prominent than the \"--cached\" and \"--index\" terms in the\n> > documentation?\n>\n> For git-checkout I think --index and --cached fit. For restore-files,\n> if you come up with better names, I'll gladly use that. Otherwise I'll\n> just use these.\n\nI've changed my mind. I'm not using --index and --cached for \"git\nrestore\" (formerly \"git restore-files\"). So how about this?\n\ngit restore --from=<tree> <pathspec> will update both the index and worktree.\n\ngit restore --from=<tree> --keep-index <pathspec> will not update the index\n\ngit restore --from=<tree> --keep-worktree <pathspec> will not update worktree\n\nAnd I'm thinking of adding these to \"git reset\" too. It will have the\nforth form:\n\ngit reset [--keep-index] [--keep-worktree] [--keep-nothing] [<commit>]\n\nwhich is similar to --soft, --mixed and --hard, but with better names:\n--soft is --keep-worktree and --keep-index, --mixed is --keep-worktree\nand --hard is --keep-nothing (i.e. the only change is HEAD).\n\nAlthough, if I work it out, I might just ignore \"git reset\" and make\nsure \"git switch\" and \"git restore\" can do whatever \"git reset\" can\nthen remove its \"common command\" status. This part is more thinking\nout loud, but \"git switch\" can have a new form\n\ngit switch --reset-branch [--keep-worktree] [--keep-index] <start-point>\n\nwhich resets \"HEAD\" (and switch of course) but do not enter detached\nmode. This covers a common use case of \"git reset [options] <commit>\".\nThen either \"git restore\" learns about \"--abort-in-progress\" to abort\ncherry-pick/merge/revert, or those commands have a new --abort and\n--quit option...\n-- \nDuy\n"},{"id":"368258","messageId":"xmqq7eek3ax7.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CACsJy8Bk=wbgzsE+Vo4w_u0E63PdUxxcvG-7e6Hq-8_jrmSErw@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-31T19:05:24Z","receivedAt":"2019-01-31T19:05:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> I've changed my mind. I'm not using --index and --cached for \"git\n> restore\" (formerly \"git restore-files\"). So how about this?\n>\n> git restore --from=<tree> <pathspec> will update both the index and worktree.\n>\n> git restore --from=<tree> --keep-index <pathspec> will not update the index\n>\n> git restore --from=<tree> --keep-worktree <pathspec> will not update worktree\n\nAn action to \"restore\" with an option to \"keep\" (i.e. \"do not\ntouch\") smells strongly of double negation.  We are restoring,\ni.e. grabbing something that existed in the past out of another\nplace (like tree or index) and depositing it to the working tree to\nrecover its previous state, oh, not but not touching the content of\nthe working tree (or the index) intact?\n\nIt would be great if you can come up with phrasing that avoids\nspecifying what is *not* done, but instructs the command what is to\nbe done, perhaps along the lines of \"restore --index-only\", \"restore\n--worktree-only\" and \"restore --index-and-worktree (which would be\nthe default)\".\n\n"},{"id":"368301","messageId":"CACsJy8CHHT=9e9ti7VA4X4h3FrZcUKvLuzkL56mXLgjk4c5Qcg@mail.gmail.com","threadId":"49988","inReplyTo":"xmqq7eek3ax7.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-01T06:48:56Z","receivedAt":"2019-02-01T06:49:24Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Feb 1, 2019 at 2:05 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n> > I've changed my mind. I'm not using --index and --cached for \"git\n> > restore\" (formerly \"git restore-files\"). So how about this?\n> >\n> > git restore --from=<tree> <pathspec> will update both the index and worktree.\n> >\n> > git restore --from=<tree> --keep-index <pathspec> will not update the index\n> >\n> > git restore --from=<tree> --keep-worktree <pathspec> will not update worktree\n>\n> An action to \"restore\" with an option to \"keep\" (i.e. \"do not\n> touch\") smells strongly of double negation.  We are restoring,\n> i.e. grabbing something that existed in the past out of another\n> place (like tree or index) and depositing it to the working tree to\n> recover its previous state, oh, not but not touching the content of\n> the working tree (or the index) intact?\n\nIt is negation (though not double). The thinking was, since \"git\nrestore\" means restore everything, extra options will amend that to\n\"restore everything except ...\" and because the parts to keep are more\nimportant (i.e. data loss), highlighting it on the command sounds a\nbit better to me: \"ok i'm going to need to restore this thing, but I\nwant this part and that part to stay the same, let's type the\ncommand...\"\n\n> It would be great if you can come up with phrasing that avoids\n> specifying what is *not* done, but instructs the command what is to\n> be done, perhaps along the lines of \"restore --index-only\", \"restore\n> --worktree-only\" and \"restore --index-and-worktree (which would be\n> the default)\".\n\nMy biggest problem with --*-only is that they cannot be combined.\nThere must be an option for every valid combination. I'm still\nthinking about \"git reset\" where there are three parts to\nreset/restore: HEAD, index and worktree. So at least there's another\nvalid combination \"reset HEAD but not index nor worktree\", which would\nend becoming another option. This route does not look promising.\n\nOf course we could just do --index and --worktree, each option\nrestores the respective part. Then it's combinable (and extensible in\nthe future). But then \"git restore\" means \"git restore --index\n--worktree\" and typing \"git restore --index\" effectively removes the\ndefault \"--worktree\", which seems a bit twisted.\n-- \nDuy\n"},{"id":"368345","messageId":"xmqqlg2zz90l.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CACsJy8CHHT=9e9ti7VA4X4h3FrZcUKvLuzkL56mXLgjk4c5Qcg@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-01T17:57:46Z","receivedAt":"2019-02-01T17:57:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> Of course we could just do --index and --worktree, each option\n> restores the respective part. Then it's combinable (and extensible in\n> the future). But then \"git restore\" means \"git restore --index\n> --worktree\" and typing \"git restore --index\" effectively removes the\n> default \"--worktree\", which seems a bit twisted.\n\nOr \"git restore --no-worktree\" (essentially, instead of saying\n\"keep\", say \"no\" to mean \"negation\").\n\nIncidentally, \"git restore --no-index\" does not have a counterpart\nin \"git checkout\", but I think it is probably a good thing to add;\nas it has to do far more than \"git cat-file blob $tree:$path >$path\"\nthese days.\n"},{"id":"368403","messageId":"CACsJy8BsVWtn5MdWCDwDfGq5SHgzK7CDvhhscKi+EJ_5Q_D9jg@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqlg2zz90l.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-02T10:57:01Z","receivedAt":"2019-02-02T10:57:31Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Feb 2, 2019 at 12:57 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n> > Of course we could just do --index and --worktree, each option\n> > restores the respective part. Then it's combinable (and extensible in\n> > the future). But then \"git restore\" means \"git restore --index\n> > --worktree\" and typing \"git restore --index\" effectively removes the\n> > default \"--worktree\", which seems a bit twisted.\n>\n> Or \"git restore --no-worktree\" (essentially, instead of saying\n> \"keep\", say \"no\" to mean \"negation\").\n>\n> Incidentally, \"git restore --no-index\" does not have a counterpart\n> in \"git checkout\", but I think it is probably a good thing to add;\n> as it has to do far more than \"git cat-file blob $tree:$path >$path\"\n> these days.\n\nOh yes, I occasionally need that too.\n-- \nDuy\n"},{"id":"368938","messageId":"cff853ae-9339-3827-26af-273a6cf10ec6@talktalk.net","threadId":"49988","inReplyTo":"20190124011244.GE34357@google.com","subject":"Re: [PATCH v3 7/8] checkout: introduce --{,no-}overlay option","fromName":"Philip Oakley","fromEmail":"philipoakley@talktalk.net","sentAt":"2019-02-09T18:54:16Z","receivedAt":"2019-02-09T19:02:29Z","isPatch":true,"sender":{"key":"philipoakley@talktalk.net","avatar":null},"body":"Hi,\n\nOn 24/01/2019 01:12, Jonathan Nieder wrote:\n> Hi,\n>\n> Junio C Hamano wrote:\n>> Thomas Gummerer<t.gummerer@gmail.com>  writes:\n>>> Jonathan Nieder wrote:\n>>>> Is this analogous to \"git add --ignore-removal\"?  If so, can we just\n>>>> call it --ignore-removal?\n>>> Yes, it seems like they are very similar.\n>> Hmm, I am not sure if the word \"removal\" makes sense in the context\n>> of \"checkout\", as \"removal\" is an_action_  just like \"checking out\"\n>> itself is, and not a_state_.  You'd check out a state out of a tree\n>> to the index and the working tree, so \"checking out absence of a\n>> path\" may make sense, though, as \"absence of a path\" is a state\n>> recorded in that source tree object.\n> I find --ignore-removal fairly easy to understand, and I had no idea\n> what --overlay would mean.\n\nI too had difficulty initially as to what 'overlay' meant, or that there \nwere options.\n\n\n>\n> I realize this is just one user's experience.  I'd be happy to do a\n> little informal survey (e.g. taking the description from the manpage\n> and asking people to name the option) if that's useful.\n>\n> See alsohttps://dl.acm.org/citation.cfm?id=32212  on this subject.\n\nI did locate a copy at \nhttp://zhang.ist.psu.edu/teaching/501/readings/Furnas.pdf\n\nThe whole word choosing problem does smack a bit of Orwell's Vocabulary \nC (OVC) where:\n\n\"The [Newspeak] C vocabulary encompasses words that relate specifically \nto science and to technical fields and disciplines. It is designed to \nensure that technical knowledge remains segmented among many fields, so \nthat no one individual can gain access to too much knowledge. In fact, \nthere is no word for “science” \" [1]\n\nMost of the DVCS concepts have a newness to them that means that we \ndon't have good words yet, hence the difficulties. Just my 2 cents.\n\n>> The word \"removal\" makes little sense in \"git add --ignore-removal\",\n>> but it and \"git add --no-all\" outlived their usefulness already, so\n>> it may not be worth_fixing_  it.  But I am mildly opposed to spread\n>> the earlier mistake to a new option.\n> I think that's a good place to end up: once we flip the default for\n> checkout, then --ignore-removal would be an obscure option in that\n> command as well.  The consistency with \"git add\" is just a bonus.\n>\n> Thanks,\n> Jonathan\n\nPhilip\n\n[1] https://www.sparknotes.com/lit/1984/section11/\n\n"},{"id":"369612","messageId":"CACsJy8CQhWeC3b6eGPePuRejfOx7c17X61-wqq5kOiRzYkRESw@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqlg2zz90l.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-19T04:20:48Z","receivedAt":"2019-02-19T04:21:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Feb 2, 2019 at 12:57 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n> > Of course we could just do --index and --worktree, each option\n> > restores the respective part. Then it's combinable (and extensible in\n> > the future). But then \"git restore\" means \"git restore --index\n> > --worktree\" and typing \"git restore --index\" effectively removes the\n> > default \"--worktree\", which seems a bit twisted.\n>\n> Or \"git restore --no-worktree\" (essentially, instead of saying\n> \"keep\", say \"no\" to mean \"negation\").\n>\n> Incidentally, \"git restore --no-index\" does not have a counterpart\n> in \"git checkout\", but I think it is probably a good thing to add;\n> as it has to do far more than \"git cat-file blob $tree:$path >$path\"\n> these days.\n\nOK this hopefully will be the final design\n\n(git restore) \"[--worktree] <paths>\" restores worktree paths from index\n\n\"--index <paths>\" restores the index from HEAD (aka \"git reset\")\n\n\"--source <tree> (--index|--worktree) <paths>\" restores index or\nworktree (or both) from <tree>\n\nI'm a bit reluctant to support \"git restore --index --worktree\n<paths>\" without --source, which should default to HEAD, since it's a\nbit unclear/inconsistent (\"git restore --worktree <paths>\" defaults to\nindex as the source, but here we use a different default source).\n-- \nDuy\n"},{"id":"369645","messageId":"CABPp-BGkJOgKqE_vHsA1fkjQ80U10Hv7-HCvScq7WOgj1UF9=Q@mail.gmail.com","threadId":"49988","inReplyTo":"CACsJy8CQhWeC3b6eGPePuRejfOx7c17X61-wqq5kOiRzYkRESw@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2019-02-19T14:42:29Z","receivedAt":"2019-02-19T14:42:43Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Duy,\n\nOn Mon, Feb 18, 2019 at 8:21 PM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Sat, Feb 2, 2019 at 12:57 AM Junio C Hamano <gitster@pobox.com> wrote:\n> >\n> > Duy Nguyen <pclouds@gmail.com> writes:\n> >\n> > > Of course we could just do --index and --worktree, each option\n> > > restores the respective part. Then it's combinable (and extensible in\n> > > the future). But then \"git restore\" means \"git restore --index\n> > > --worktree\" and typing \"git restore --index\" effectively removes the\n> > > default \"--worktree\", which seems a bit twisted.\n> >\n> > Or \"git restore --no-worktree\" (essentially, instead of saying\n> > \"keep\", say \"no\" to mean \"negation\").\n> >\n> > Incidentally, \"git restore --no-index\" does not have a counterpart\n> > in \"git checkout\", but I think it is probably a good thing to add;\n> > as it has to do far more than \"git cat-file blob $tree:$path >$path\"\n> > these days.\n>\n> OK this hopefully will be the final design\n>\n> (git restore) \"[--worktree] <paths>\" restores worktree paths from index\n>\n> \"--index <paths>\" restores the index from HEAD (aka \"git reset\")\n>\n> \"--source <tree> (--index|--worktree) <paths>\" restores index or\n> worktree (or both) from <tree>\n>\n> I'm a bit reluctant to support \"git restore --index --worktree\n> <paths>\" without --source, which should default to HEAD, since it's a\n> bit unclear/inconsistent (\"git restore --worktree <paths>\" defaults to\n> index as the source, but here we use a different default source).\n\nSorry for going missing a while from the conversation, and thanks so\nmuch for pushing this forward.\n\nOverall this looks good, but there's just one part that confuses me.\nHere you seem to suggest that if you pass --source but neither --index\nor --worktree that both the index and working tree will be written to.\nWhy are \"restored\" changes considered ready for commit?  That seems\nconfusing to me (and was one of the bugs of checkout, IMO).  See also\nsecond half of https://public-inbox.org/git/xmqq1s6yezk3.fsf@gitster-ct.c.googlers.com/\n\nElijah\n"},{"id":"369647","messageId":"CACsJy8AqcCgMLObhpgPmWV261c1zQaaZNHXOO8w_VXMoW0pm0Q@mail.gmail.com","threadId":"49988","inReplyTo":"CABPp-BGkJOgKqE_vHsA1fkjQ80U10Hv7-HCvScq7WOgj1UF9=Q@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-19T14:57:57Z","receivedAt":"2019-02-19T14:58:26Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Feb 19, 2019 at 9:42 PM Elijah Newren <newren@gmail.com> wrote:\n> > OK this hopefully will be the final design\n> >\n> > (git restore) \"[--worktree] <paths>\" restores worktree paths from index\n> >\n> > \"--index <paths>\" restores the index from HEAD (aka \"git reset\")\n> >\n> > \"--source <tree> (--index|--worktree) <paths>\" restores index or\n> > worktree (or both) from <tree>\n> >\n> > I'm a bit reluctant to support \"git restore --index --worktree\n> > <paths>\" without --source, which should default to HEAD, since it's a\n> > bit unclear/inconsistent (\"git restore --worktree <paths>\" defaults to\n> > index as the source, but here we use a different default source).\n>\n> Sorry for going missing a while from the conversation, and thanks so\n> much for pushing this forward.\n>\n> Overall this looks good, but there's just one part that confuses me.\n> Here you seem to suggest that if you pass --source but neither --index\n> or --worktree that both the index and working tree will be written to.\n\nNo no. Sorry for not being clear. If neither --index or --worktree is\ngiven, the default will be --worktree. --source changes the \"source\"\nbut cannot influence target selection. So \"git restore --source=HEAD\nfoo.c\" will restore foo.c on the worktree but not the index. I still\nremember that point you and Stefan Xenos raised ;-)\n\nFull git-restore.txt is here if you're interested. I think I'll send\nit out soon once git-switch part more or less settles.\n\nhttps://gitlab.com/pclouds/git/blob/switch-and-restore-forever/Documentation/git-restore.txt\n\n> Why are \"restored\" changes considered ready for commit?  That seems\n> confusing to me (and was one of the bugs of checkout, IMO).  See also\n> second half of https://public-inbox.org/git/xmqq1s6yezk3.fsf@gitster-ct.c.googlers.com/\n>\n> Elijah\n\n\n\n-- \nDuy\n"},{"id":"369658","messageId":"xmqqwolv1tzw.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CACsJy8CQhWeC3b6eGPePuRejfOx7c17X61-wqq5kOiRzYkRESw@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-19T19:02:59Z","receivedAt":"2019-02-19T19:03:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Sat, Feb 2, 2019 at 12:57 AM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> Duy Nguyen <pclouds@gmail.com> writes:\n>>\n>> > Of course we could just do --index and --worktree, each option\n>> > restores the respective part. Then it's combinable (and extensible in\n>> > the future). But then \"git restore\" means \"git restore --index\n>> > --worktree\" and typing \"git restore --index\" effectively removes the\n>> > default \"--worktree\", which seems a bit twisted.\n>>\n>> Or \"git restore --no-worktree\" (essentially, instead of saying\n>> \"keep\", say \"no\" to mean \"negation\").\n>>\n>> Incidentally, \"git restore --no-index\" does not have a counterpart\n>> in \"git checkout\", but I think it is probably a good thing to add;\n>> as it has to do far more than \"git cat-file blob $tree:$path >$path\"\n>> these days.\n>\n> OK this hopefully will be the final design\n>\n> (git restore) \"[--worktree] <paths>\" restores worktree paths from index\n>\n> \"--index <paths>\" restores the index from HEAD (aka \"git reset\")\n>\n> \"--source <tree> (--index|--worktree) <paths>\" restores index or\n> worktree (or both) from <tree>\n>\n> I'm a bit reluctant to support \"git restore --index --worktree\n> <paths>\" without --source, which should default to HEAD, since it's a\n> bit unclear/inconsistent (\"git restore --worktree <paths>\" defaults to\n> index as the source, but here we use a different default source).\n\nOk, so we grab things from the index by default, but with --source\n<tree>, we can tell the command to grab things from the tree.  When\nwe are explicitly told to update the index with \"--index\", it would\nbe nonsense to grab things from the index, so \"--source <tree>\"\nbecomes required in that case.  Makes sense.\n\nTo summerize and full enumerate all the allowed variants:\n\n * --index --worktree --source <tree> <path>...\n\n   Update both from a tree; --source <tree> is required.\n\n * --index --no-worktree --source <tree> <path>...\n\n   Update only the index but not the working tree; --source <tree>\n   is required.\n\n\n * --no-index --worktree <path>...\n\n   Update only the working tree files without touching the index\n   (new feature that cannot be done with the current Git, although\n   \"cat-file -p >path\" may be close enough at times), from the index\n\n * --no-index --worktree --source <tree> <path>...\n\n   Update only the working tree files without touching the index\n   from a tree-ish.\n\n * --no-index --no-worktree <path>...\n\n   Update nothing, which is a no-op that is not all that useful.\n\n * --no-index --no-worktree --source <tree> <path>...\n\n   Update nothing, which is a no-op that is not all that useful.\n\nI am getting the impression that to save typing, you would want to\nmake \"--index --worktree\" the default (i.e. among the above, only\n--no-index and --no-worktree need to be spelled explicitly), but\nthere is one glitch.  Updating from the index must be spelled\nexplicitly with \"--no-index --worktree\".\n\nSo perhaps the defaulting rule for the \"--index\" option must become\na bit more tricky.  Perhaps the rules are:\n\n * --worktree is the defeault; --no-worktree can be given from the\n   command line to countermand it, and --worktree can be given from\n   the command line to be more explicit.\n\n * when --source <tree> is given from the command line, --index is\n   the default, and --no-index can be given to countermand it.\n\n * when --source <tree> is not given from the command line,\n   --no-index is the only sensible choice.  It can be given from the\n   command line to be more explicit, but giving --index to\n   countermand the --no-index default would be an error, as updating\n   the index, whether the same update also goes to the working tree,\n   must come from a --source <tree>.\n\nAm I following you correctly?\n\nThanks.\n"},{"id":"369659","messageId":"xmqqsgwj1ts9.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CABPp-BGkJOgKqE_vHsA1fkjQ80U10Hv7-HCvScq7WOgj1UF9=Q@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-19T19:07:34Z","receivedAt":"2019-02-19T19:07:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> Overall this looks good, but there's just one part that confuses me.\n> Here you seem to suggest that if you pass --source but neither --index\n> or --worktree that both the index and working tree will be written to.\n> Why are \"restored\" changes considered ready for commit?  That seems\n> confusing to me (and was one of the bugs of checkout, IMO).  See also\n> second half of https://public-inbox.org/git/xmqq1s6yezk3.fsf@gitster-ct.c.googlers.com/\n\nAs long as worktree-only mode does not lose track of a\npreviously-untracked path in the index (perhaps use the i-t-a bit),\nI do not have a strong objection against making the worktree-only\nmode the default.\n\n"},{"id":"369660","messageId":"xmqqo9771tnj.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"xmqqwolv1tzw.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-19T19:10:24Z","receivedAt":"2019-02-19T19:10:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I am getting the impression that to save typing, you would want to\n> make \"--index --worktree\" the default (i.e. among the above, only\n> --no-index and --no-worktree need to be spelled explicitly), but\n> there is one glitch.  Updating from the index must be spelled\n> explicitly with \"--no-index --worktree\".\n\nAnd after getting reminded by Elijah, the default pair is\n<--no-index, --worktree>.\n\n> So perhaps the defaulting rule for the \"--index\" option must become\n> a bit more tricky.  Perhaps the rules are:\n>\n>  * --worktree is the default; --no-worktree can be given from the\n>    command line to countermand it, and --worktree can be given from\n>    the command line to be more explicit.\n>\n>  * when --source <tree> is given from the command line, --index is\n>    the default, and --no-index can be given to countermand it.\n\nCorrection.\n\n    * when --source <tree> is given, --no-index is the default, but\n      --index can be given to countermand it.\n\n>\n>  * when --source <tree> is not given from the command line,\n>    --no-index is the only sensible choice.  It can be given from the\n>    command line to be more explicit, but giving --index to\n>    countermand the --no-index default would be an error, as updating\n>    the index, whether the same update also goes to the working tree,\n>    must come from a --source <tree>.\n\nThis is still correct.\n"},{"id":"369669","messageId":"CABPp-BERuEtdjHhqaao+2=rsLXiPdkG4SbeULQ6=59hgWS5BLg@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqo9771tnj.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2019-02-19T22:04:56Z","receivedAt":"2019-02-19T22:05:11Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Feb 19, 2019 at 11:10 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n> > I am getting the impression that to save typing, you would want to\n> > make \"--index --worktree\" the default (i.e. among the above, only\n> > --no-index and --no-worktree need to be spelled explicitly), but\n> > there is one glitch.  Updating from the index must be spelled\n> > explicitly with \"--no-index --worktree\".\n>\n> And after getting reminded by Elijah, the default pair is\n> <--no-index, --worktree>.\n\nWhy would you want --no-index or --no-worktree as flags?  That seems\nto presume a default of modifying both the index and the working tree,\nas these names imply undoing pieces of such a default.\n\nI'd rather have a flag like --worktree which alone only modifies the\nworking tree and is presumed to be the default (but useful to be\nexplicit or as mentioned later), have a flag for applying the changes\nto the index instead (--index?), and treat applying to both the\nworking tree and the index as unusual and require either both flags\n(--worktree --index ?) or some special flag that likely has a longer\nname (--worktree-and-index?).\n\nI _think_ Duy does the latter reading over his manpage that he linked\nto, but maybe I'm just reading my own biases into it.\n"},{"id":"369671","messageId":"CABPp-BEsK8grsGCMq9-QCWd4fgYzm7GfzQudbhFvGj_C55LNyA@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqwolv1tzw.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2019-02-19T22:13:52Z","receivedAt":"2019-02-19T22:14:07Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Feb 19, 2019 at 11:03 AM Junio C Hamano <gitster@pobox.com> wrote:\n>  * --no-index --worktree <path>...\n>\n>    Update only the working tree files without touching the index\n>    (new feature that cannot be done with the current Git, although\n>    \"cat-file -p >path\" may be close enough at times), from the index\n\nI worry slightly that wording like this might paint ourselves into a\nsimilar corner of only correctly handling files as paths, rather than\nalso handling directories as paths, and/or which presumes the\nno-overlay mode that I find problematic.  Maybe your \"at times\" just\nmeant \"when dealing with a path that is a file that existed in the\ngiven source\", but I wonder if you are pushing more than that?\n"},{"id":"369672","messageId":"CABPp-BGp53DrP6=FpYpxy5cmWkcygCz_nrunXisC55KV1ydyXg@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqsgwj1ts9.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2019-02-19T22:24:28Z","receivedAt":"2019-02-19T22:24:43Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Feb 19, 2019 at 11:07 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > Overall this looks good, but there's just one part that confuses me.\n> > Here you seem to suggest that if you pass --source but neither --index\n> > or --worktree that both the index and working tree will be written to.\n> > Why are \"restored\" changes considered ready for commit?  That seems\n> > confusing to me (and was one of the bugs of checkout, IMO).  See also\n> > second half of https://public-inbox.org/git/xmqq1s6yezk3.fsf@gitster-ct.c.googlers.com/\n>\n> As long as worktree-only mode does not lose track of a\n> previously-untracked path in the index (perhaps use the i-t-a bit),\n> I do not have a strong objection against making the worktree-only\n> mode the default.\n\nCould you unpack that for me a bit?  My assumption is that\nworktree-only mode doesn't touch the index (other than maybe reading\nfrom it), and treating the index as read-only means by definition it\ncan't lose anything from there -- but then you mentioned using the\nintent-to-add bit, and I feel like I'm missing an important puzzle\npiece somewhere.  Trying to make sense of it, I'm wondering if you are\nobjecting to using overlay mode in general, or are trying to connect\nthis to the new \"precious\" concept being advanced, or if there's\nsomething else you are considering here.\n"},{"id":"369673","messageId":"xmqq1s431kf0.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CABPp-BERuEtdjHhqaao+2=rsLXiPdkG4SbeULQ6=59hgWS5BLg@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-19T22:29:55Z","receivedAt":"2019-02-19T22:30:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Tue, Feb 19, 2019 at 11:10 AM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>> Junio C Hamano <gitster@pobox.com> writes:\n>>\n>> > I am getting the impression that to save typing, you would want to\n>> > make \"--index --worktree\" the default (i.e. among the above, only\n>> > --no-index and --no-worktree need to be spelled explicitly), but\n>> > there is one glitch.  Updating from the index must be spelled\n>> > explicitly with \"--no-index --worktree\".\n>>\n>> And after getting reminded by Elijah, the default pair is\n>> <--no-index, --worktree>.\n>\n> Why would you want --no-index or --no-worktree as flags?  That seems\n> to presume a default of modifying both the index and the working tree,\n> as these names imply undoing pieces of such a default.\n\nBy \"flags\" I think you mean \"treat them as two orthogonal booleans\"?\n\nIt was just how I read Duy's examples (especially the \"both --index\nand --worktree given\" example where \"--source <tree>\" becomes\nmandatory).  I do not have strong preference either way myself, but\nI tend to think that treating these as two independent booleans\nwould be a way to make it clear that the new design departs from\nwhat we have been doing (i.e. \"--index\" means \"both\", \"--cached\"\nmeans \"index only\" and if we were to introduce the \"cat-file -p >\"\nvariant that would be called \"--worktree-only\"; in these, there is\nno \"two orthogonal booleans\" that can be mixed---instead they come\npremixed).\n\n> I'd rather have a flag like --worktree which alone only modifies the\n> working tree and is presumed to be the default (but useful to be\n> explicit or as mentioned later), have a flag for applying the changes\n> to the index instead (--index?), and treat applying to both the\n> working tree and the index as unusual and require either both flags\n> (--worktree --index ?) or some special flag that likely has a longer\n> name (--worktree-and-index?).\n\nSo you are in favor of pre-mixed set of options, all are mutually\nexclusive.  Which I am perfectly fine with.\n\n\nI however do think \"both worktree and index\" is quite common when\ntweaking the tree to prepare for the next commit.  A path with\ncontents freshly taken out of an existing tree may not match exactly\nwhat you plan to record in your next commit, and you would not be\nrecording it immediately in a commit as-is.  But having the contents\ntaken from an existing tree recorded as the baseline in the index\nwould make \"git diff (no tree-ish) <path>\" a handy tool to review\nyour progress toward the next commit since that baseline state, in\naddition to \"git diff HEAD <path>\" that is the usual \"how does the\noverall change relative to the parent of the commit I am preparing\nfor look like\".\n\nSo I'd hesitate to endorse \"a deliberately longer and harder to type\noption\" to populate both the index and the working tree files at the\nsame time.\n\n"},{"id":"369675","messageId":"xmqqwolvz9wj.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CABPp-BEsK8grsGCMq9-QCWd4fgYzm7GfzQudbhFvGj_C55LNyA@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-19T22:33:00Z","receivedAt":"2019-02-19T22:33:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> On Tue, Feb 19, 2019 at 11:03 AM Junio C Hamano <gitster@pobox.com> wrote:\n>>  * --no-index --worktree <path>...\n>>\n>>    Update only the working tree files without touching the index\n>>    (new feature that cannot be done with the current Git, although\n>>    \"cat-file -p >path\" may be close enough at times), from the index\n>\n> I worry slightly that wording like this might paint ourselves into a\n> similar corner of only correctly handling files as paths, rather than\n> also handling directories as paths, and/or which presumes the\n> no-overlay mode that I find problematic.  Maybe your \"at times\" just\n> meant \"when dealing with a path that is a file that existed in the\n> given source\", but I wonder if you are pushing more than that?\n\nNo, I meant \"when you are not doing smudge filters (including eol\nconversion)\", aka \"'cat-file -p' gives you raw blob contents, which\nmay not be what you want in your worktree.\"\n\n\n\n\n"},{"id":"369676","messageId":"xmqqsgwjz9q1.fsf@gitster-ct.c.googlers.com","threadId":"49988","inReplyTo":"CABPp-BGp53DrP6=FpYpxy5cmWkcygCz_nrunXisC55KV1ydyXg@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-19T22:36:54Z","receivedAt":"2019-02-19T22:37:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n>> As long as worktree-only mode does not lose track of a\n>> previously-untracked path in the index (perhaps use the i-t-a bit),\n>> I do not have a strong objection against making the worktree-only\n>> mode the default.\n>\n> Could you unpack that for me a bit?\n\nSuppose in an ancient version v1.0 there was a file called\nREADME.txt but these days such a file does not exist (there may be\nREADME.md added though).  By default, the command does not stuff the\ncontents to the index out of the tree and instead operate only on\nthe working tree.\n\n  $ git restore-path --source v1.0 README.txt\n\nAt this point, you are assuming that README.txt will become\nuntracked and the user needs to manually add it.  I was asking if it\nmakes sense to at least make the index \"aware of\" it with I-T-A bit,\nand I am leaning towards answering \"yes\" to that question.\n\n\n"},{"id":"369678","messageId":"CABPp-BE19yVzDife5PqdQGmKrwrffoOt2KzBisgbqxaGry7LBw@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqsgwjz9q1.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2019-02-19T23:00:44Z","receivedAt":"2019-02-19T23:00:59Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Feb 19, 2019 at 2:36 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> >> As long as worktree-only mode does not lose track of a\n> >> previously-untracked path in the index (perhaps use the i-t-a bit),\n> >> I do not have a strong objection against making the worktree-only\n> >> mode the default.\n> >\n> > Could you unpack that for me a bit?\n>\n> Suppose in an ancient version v1.0 there was a file called\n> README.txt but these days such a file does not exist (there may be\n> README.md added though).  By default, the command does not stuff the\n> contents to the index out of the tree and instead operate only on\n> the working tree.\n>\n>   $ git restore-path --source v1.0 README.txt\n>\n> At this point, you are assuming that README.txt will become\n> untracked and the user needs to manually add it.  I was asking if it\n> makes sense to at least make the index \"aware of\" it with I-T-A bit,\n> and I am leaning towards answering \"yes\" to that question.\n\nAh, thanks for all the clarifications (for this and the other emails).\nYour suggestion here would mean that --worktree alone wouldn't\nactually treat the index as read-only, but I too am leaning towards\nthe thought that it makes sense to set the i-t-a bit for such cases.\n"},{"id":"369689","messageId":"CACsJy8BD7OoO-K_ww-QssDiAK7Yi9zy5binGvQ6GBJvvt2f8iA@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqsgwjz9q1.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-20T01:53:09Z","receivedAt":"2019-02-20T01:53:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Feb 20, 2019 at 5:36 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> >> As long as worktree-only mode does not lose track of a\n> >> previously-untracked path in the index (perhaps use the i-t-a bit),\n> >> I do not have a strong objection against making the worktree-only\n> >> mode the default.\n> >\n> > Could you unpack that for me a bit?\n>\n> Suppose in an ancient version v1.0 there was a file called\n> README.txt but these days such a file does not exist (there may be\n> README.md added though).  By default, the command does not stuff the\n> contents to the index out of the tree and instead operate only on\n> the working tree.\n>\n>   $ git restore-path --source v1.0 README.txt\n>\n> At this point, you are assuming that README.txt will become\n> untracked and the user needs to manually add it.  I was asking if it\n> makes sense to at least make the index \"aware of\" it with I-T-A bit,\n> and I am leaning towards answering \"yes\" to that question.\n\nI completely forgot about i-t-a! Do we want the command to add i-t-a\nbit by default, or only when --intent-to-add is specified? So far\ni-t-a has been a conscious choice, both \"git reset <commit>\" and \"git\nadd\" require --intent-to-add to use it. The first safe step could be\nrequire --intent-to-add even in git-restore, then we could introduce a\nconfig key that enables --intent-to-add in both \"git restore\" and \"git\nreset\" (and perhaps \"git apply\" later, I still need to finish that\npart).\n-- \nDuy\n"},{"id":"369690","messageId":"CACsJy8AMXkkpJjR5hB2PH7ZyRyyjU2goQx7k7AsQogpzu95QKw@mail.gmail.com","threadId":"49988","inReplyTo":"xmqqo9771tnj.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-20T02:19:07Z","receivedAt":"2019-02-20T02:19:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Feb 20, 2019 at 2:10 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n> > I am getting the impression that to save typing, you would want to\n> > make \"--index --worktree\" the default (i.e. among the above, only\n> > --no-index and --no-worktree need to be spelled explicitly), but\n> > there is one glitch.  Updating from the index must be spelled\n> > explicitly with \"--no-index --worktree\".\n>\n> And after getting reminded by Elijah, the default pair is\n> <--no-index, --worktree>.\n>\n> > So perhaps the defaulting rule for the \"--index\" option must become\n> > a bit more tricky.  Perhaps the rules are:\n> >\n> >  * --worktree is the default; --no-worktree can be given from the\n> >    command line to countermand it, and --worktree can be given from\n> >    the command line to be more explicit.\n\nI originally went with that (--no-worktree to negate default\nsettings), but after updating docs to use \"git restore\" it's just too\nmuch to write. My current rules are\n\n - default is --worktree\n - as soon as any of --[no-]worktree or --[no-]index is specified, the\nabove line is void. There is no default, what you specify is what you\nget.\n\nWhile it's a bit more twisted than spelling out --no-worktree to\ncountermand the default, i think it's more natural to think and write\nit: ok i'm going to need to restore this and that so I write --this\nand --that. Going with --no-worktree you need to think \"i need to\nwrite this and that and counter the default which is that other\nthing\". We essentially have two modes, the default mode and explicit\nmode. Too bad?\n\n> >  * when --source <tree> is given from the command line, --index is\n> >    the default, and --no-index can be given to countermand it.\n>\n> Correction.\n>\n>     * when --source <tree> is given, --no-index is the default, but\n>       --index can be given to countermand it.\n>\n> >\n> >  * when --source <tree> is not given from the command line,\n> >    --no-index is the only sensible choice.  It can be given from the\n> >    command line to be more explicit, but giving --index to\n> >    countermand the --no-index default would be an error, as updating\n> >    the index, whether the same update also goes to the working tree,\n> >    must come from a --source <tree>.\n>\n> This is still correct.\n\nSo I guess I scratch the default source for \"--index --no-worktree\"\n(or just --index in my rules above) then? It does make sense to\ndefault restoring the index from HEAD. And it makes \"git status\"\nsuggestion to unstage a bit shorter (\"git restore --index <paths>\"\ninstead of \"git restore --source=HEAD --index <paths>\")\n-- \nDuy\n"},{"id":"369691","messageId":"CACsJy8AkbWPx10w2vQYhywk4HbEfVaAZ4vDr4X=pvsLDK6DkvA@mail.gmail.com","threadId":"49988","inReplyTo":"xmqq1s431kf0.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-20T02:32:11Z","receivedAt":"2019-02-20T02:32:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Feb 20, 2019 at 5:29 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Elijah Newren <newren@gmail.com> writes:\n>\n> > On Tue, Feb 19, 2019 at 11:10 AM Junio C Hamano <gitster@pobox.com> wrote:\n> >>\n> >> Junio C Hamano <gitster@pobox.com> writes:\n> >>\n> >> > I am getting the impression that to save typing, you would want to\n> >> > make \"--index --worktree\" the default (i.e. among the above, only\n> >> > --no-index and --no-worktree need to be spelled explicitly), but\n> >> > there is one glitch.  Updating from the index must be spelled\n> >> > explicitly with \"--no-index --worktree\".\n> >>\n> >> And after getting reminded by Elijah, the default pair is\n> >> <--no-index, --worktree>.\n> >\n> > Why would you want --no-index or --no-worktree as flags?  That seems\n> > to presume a default of modifying both the index and the working tree,\n> > as these names imply undoing pieces of such a default.\n>\n> By \"flags\" I think you mean \"treat them as two orthogonal booleans\"?\n>\n> It was just how I read Duy's examples (especially the \"both --index\n> and --worktree given\" example where \"--source <tree>\" becomes\n> mandatory).  I do not have strong preference either way myself, but\n> I tend to think that treating these as two independent booleans\n> would be a way to make it clear that the new design departs from\n> what we have been doing (i.e. \"--index\" means \"both\", \"--cached\"\n> means \"index only\" and if we were to introduce the \"cat-file -p >\"\n> variant that would be called \"--worktree-only\"; in these, there is\n> no \"two orthogonal booleans\" that can be mixed---instead they come\n> premixed).\n\nThere is indeed inconsistency in \"git status\" advice with my patches,\nwhere it suggests both \"git restore --index\" and \"git rm --cached\",\nboth operate only in the index but with different option name.\n\n\"--index --no-worktree\" is one way to deal with this. Another way may\nbe avoid --index in git-restore and use another name like\n--staging-area or something? That avoids the name clash, and we could\neven add --worktree and --staging-area to \"git rm\" / \"git apply\"\nlater, deprecating (but still supporting) --index and --cached there.\n-- \nDuy\n"},{"id":"369692","messageId":"CACsJy8BbBx4jrmUKsDOEGcQay5FuGfc0DzCUjkYKLaq21yimVQ@mail.gmail.com","threadId":"49988","inReplyTo":"CABPp-BERuEtdjHhqaao+2=rsLXiPdkG4SbeULQ6=59hgWS5BLg@mail.gmail.com","subject":"Re: [PATCH 6/8] checkout: add --cached option","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-20T03:52:03Z","receivedAt":"2019-02-20T03:52:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Feb 20, 2019 at 5:05 AM Elijah Newren <newren@gmail.com> wrote:\n>\n> On Tue, Feb 19, 2019 at 11:10 AM Junio C Hamano <gitster@pobox.com> wrote:\n> >\n> > Junio C Hamano <gitster@pobox.com> writes:\n> >\n> > > I am getting the impression that to save typing, you would want to\n> > > make \"--index --worktree\" the default (i.e. among the above, only\n> > > --no-index and --no-worktree need to be spelled explicitly), but\n> > > there is one glitch.  Updating from the index must be spelled\n> > > explicitly with \"--no-index --worktree\".\n> >\n> > And after getting reminded by Elijah, the default pair is\n> > <--no-index, --worktree>.\n>\n> Why would you want --no-index or --no-worktree as flags?  That seems\n> to presume a default of modifying both the index and the working tree,\n> as these names imply undoing pieces of such a default.\n>\n> I'd rather have a flag like --worktree which alone only modifies the\n> working tree and is presumed to be the default (but useful to be\n> explicit or as mentioned later), have a flag for applying the changes\n> to the index instead (--index?), and treat applying to both the\n> working tree and the index as unusual and require either both flags\n> (--worktree --index ?) or some special flag that likely has a longer\n> name (--worktree-and-index?).\n\nI'd prefer separate options. I even gave --worktree and --index\nshortcuts so we could write \"git restore -IW\" if \"git restore --index\n--worktree\" is used often (and I think it could be an alternative for\n\"git reset --hard HEAD\" if --force is also specified)\n\n> I _think_ Duy does the latter reading over his manpage that he linked\n> to, but maybe I'm just reading my own biases into it.\n\nNah you read it right. The \"examples\" section also shows it.\n-- \nDuy\n"}]}