From: "Hugo Sales via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Hugo Sales <hugo@hsal.es>, Hugo Sales <hugo@hsal.es>
Subject: [PATCH] Add `restore.defaultLocation` option
Date: Sat, 11 Mar 2023 23:42:33 +0000 [thread overview]
Message-ID: <pull.1467.git.git.1678578153640.gitgitgadget@gmail.com> (raw)
From: Hugo Sales <hugo@hsal.es>
This options allows control over which of `--worktree` or `--staged` is
applied when `git restore` is invoked with neither
This patch is intended to reduce lost work to accidental `git restore .`
when `git restore --staged .` was intended.
Signed-off-by: Hugo Sales <hugo@hsal.es>
---
Add restore.defaultLocation option
This options allows control over which of --worktree or --staged is
applied when git restore is invoked with neither
This patch is intended to reduce lost work to accidental git restore .
when git restore --staged . was intended.
CC: Ævar Arnfjörð Bjarmason avarab@gmail.com, Jeff King peff@peff.net,
Victoria Dye vdye@github.com
------------------------------------------------------------------------
I tried to send with git send-email, but I'm having problems. My mail
provider is mailbox.org and I'm getting Command unknown: 'AUTH' at
/usr/lib/git-core/git-send-email line 1691. Apologies if it actually
went through.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1467%2Fsomeonewithpc%2Fmaster-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1467/someonewithpc/master-v1
Pull-Request: https://github.com/git/git/pull/1467
Documentation/config.txt | 2 +
Documentation/config/restore.txt | 13 ++++
Documentation/git-restore.txt | 17 +++--
builtin/checkout.c | 27 +++++++
t/t2070-restore.sh | 124 +++++++++++++++++++++++++++++++
5 files changed, 178 insertions(+), 5 deletions(-)
create mode 100644 Documentation/config/restore.txt
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0e93aef8626..4359c63794e 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -501,6 +501,8 @@ include::config/repack.txt[]
include::config/rerere.txt[]
+include::config/restore.txt[]
+
include::config/revert.txt[]
include::config/safe.txt[]
diff --git a/Documentation/config/restore.txt b/Documentation/config/restore.txt
new file mode 100644
index 00000000000..479fd13ca24
--- /dev/null
+++ b/Documentation/config/restore.txt
@@ -0,0 +1,13 @@
+restore.defaultLocation::
+ Valid values: "worktree", "staged" or "both". Controls the default
+ behavior of `git restore` without `--worktree` or `--staged`. If
+ "worktree", `git restore` without `--worktree` or `--staged` is
+ equivalent to `git restore --worktree`. If "staged", `git restore`
+ without `--worktree` or `--staged` is equivalent to `git restore
+ --staged`. If "both", `git restore` without `--worktree` or `--staged`
+ is equivalent to `git restore --worktree --staged`. Adding an option
+ overrides the default, such that if the option is set to "staged",
+ specifying `--worktree` will only affect the worktree, not both. This
+ option can be used to prevent accidentally losing work by running `git
+ restore .` when `git restore --staged .` was intended.
+ See linkgit:git-restore[1]
diff --git a/Documentation/git-restore.txt b/Documentation/git-restore.txt
index 5964810caa4..28165861f55 100644
--- a/Documentation/git-restore.txt
+++ b/Documentation/git-restore.txt
@@ -14,14 +14,18 @@ SYNOPSIS
DESCRIPTION
-----------
-Restore specified paths in the working tree with some contents from a
+Restore specified paths in the working tree or index with some contents from a
restore source. If a path is tracked but does not exist in the restore
source, it will be removed to match the source.
-The command can also be used to restore the content in the index with
+The command can be used to restore the content in the index with
`--staged`, or restore both the working tree and the index with
`--staged --worktree`.
+The config options `restore.defaultLocation`, which accepts values "worktree",
+"staged" or "both", can be used to control the default behavior for which
+flag(s) apply if neither `--staged` nor `--worktree` is supplied.
+
By default, if `--staged` is given, the contents are restored from `HEAD`,
otherwise from the index. Use `--source` to restore from a different commit.
@@ -59,9 +63,12 @@ all modified paths.
--worktree::
-S::
--staged::
- Specify the restore location. If neither option is specified,
- by default the working tree is restored. Specifying `--staged`
- will only restore the index. Specifying both restores both.
+ Specify the restore location. If neither option is specified, the
+ default depends on the `'restore.defaultLocation` config option, which
+ can be "worktree" (the default), "staged" or "both", to control which of
+ the two flags is assumed if none are given. Specifying `--worktree` will
+ only restore the worktree. Specifying `--staged` will only restore the
+ index. Specifying both restores both.
-q::
--quiet::
diff --git a/builtin/checkout.c b/builtin/checkout.c
index a5155cf55c1..5067753030b 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1922,6 +1922,30 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
return ret;
}
+static const char *checkout_default_index_worktree;
+static int git_restore_config(const char *var, const char *value, void *cb)
+{
+ struct checkout_opts *opts = cb;
+
+ if (!strcmp(var, "restore.defaultlocation")) {
+ git_config_string(&checkout_default_index_worktree, var, value);
+
+ if (!strcmp(checkout_default_index_worktree, "both")) {
+ opts->checkout_index = -2; /* default on */
+ opts->checkout_worktree = -2; /* default on */
+ } else if (!strcmp(checkout_default_index_worktree, "staged")) {
+ opts->checkout_index = -2; /* default on */
+ opts->checkout_worktree = -1; /* default off */
+ } else {
+ opts->checkout_index = -1; /* default off */
+ opts->checkout_worktree = -2; /* default on */
+ }
+ return 0;
+ }
+ return git_xmerge_config(var, value, NULL);
+}
+
+
int cmd_restore(int argc, const char **argv, const char *prefix)
{
struct checkout_opts opts;
@@ -1942,6 +1966,7 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
struct branch_info new_branch_info = { 0 };
memset(&opts, 0, sizeof(opts));
+
opts.accept_ref = 0;
opts.accept_pathspec = 1;
opts.empty_pathspec_ok = 0;
@@ -1950,6 +1975,8 @@ int cmd_restore(int argc, const char **argv, const char *prefix)
opts.checkout_worktree = -2; /* default on */
opts.ignore_unmerged_opt = "--ignore-unmerged";
+ git_config(git_restore_config, &opts);
+
options = parse_options_dup(restore_options);
options = add_common_options(&opts, options);
options = add_checkout_path_options(&opts, options);
diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh
index 7c43ddf1d99..6e9b06e0bf4 100755
--- a/t/t2070-restore.sh
+++ b/t/t2070-restore.sh
@@ -137,4 +137,128 @@ test_expect_success 'restore --staged invalidates cache tree for deletions' '
test_must_fail git rev-parse HEAD:new1
'
+test_expect_success 'restore with restore.defaultLocation unset works as if --worktree given' '
+ test_when_finished git reset --hard HEAD^ &&
+ test_commit root-unset-restore.defaultLocation &&
+ test_commit unset-restore.defaultLocation one one &&
+ > one &&
+
+ git restore one &&
+ test -z $(git status --porcelain --untracked-files=no) &&
+
+ > one &&
+ git add one &&
+ git restore one &&
+ git status --porcelain --untracked-files=no | grep "^M " &&
+
+ > one &&
+ git add one &&
+ git restore --worktree one &&
+ git status --porcelain --untracked-files=no | grep "^M " &&
+
+ git restore --staged one &&
+ git status --porcelain --untracked-files=no | grep "^ M" &&
+
+ > one &&
+ git add one &&
+ git restore --worktree --staged one &&
+ test -z $(git status --porcelain --untracked-files=no)
+'
+
+test_expect_success 'restore with restore.defaultLocation set to worktree works as if --worktree given' '
+ test_when_finished git reset --hard HEAD^ &&
+ test_when_finished git config --unset restore.defaultLocation &&
+ test_commit root-worktree-restore.defaultLocation &&
+ test_commit worktree-restore.defaultLocation one one &&
+ git config restore.defaultLocation worktree &&
+ > one &&
+
+ git restore one &&
+ test -z $(git status --porcelain --untracked-files=no) &&
+
+ > one &&
+ git add one &&
+ git restore one &&
+ git status --porcelain --untracked-files=no | grep "^M " &&
+
+ > one &&
+ git add one &&
+ git restore --worktree one &&
+ git status --porcelain --untracked-files=no | grep "^M " &&
+
+ git restore --staged one &&
+ git status --porcelain --untracked-files=no | grep "^ M" &&
+
+ > one &&
+ git add one &&
+ git restore --worktree --staged one &&
+ test -z $(git status --porcelain --untracked-files=no)
+'
+
+test_expect_success 'restore with restore.defaultLocation set to staged works as if --staged given' '
+ test_when_finished git reset --hard HEAD^ &&
+ test_when_finished git config --unset restore.defaultLocation &&
+ test_commit root-staged-restore.defaultLocation &&
+ test_commit staged-restore.defaultLocation one one &&
+ git config restore.defaultLocation staged &&
+ > one &&
+
+ git restore one &&
+ git status --porcelain --untracked-files=no | grep "^ M" &&
+
+ git restore --staged one &&
+ git status --porcelain --untracked-files=no | grep "^ M" &&
+
+ git add one &&
+ git restore one &&
+ git status --porcelain --untracked-files=no | grep "^ M" &&
+
+ git add one &&
+ git restore --staged one &&
+ git status --porcelain --untracked-files=no | grep "^ M" &&
+
+ git restore --worktree one &&
+ test -z $(git status --porcelain --untracked-files=no) &&
+
+ > one &&
+ git add one &&
+ git restore --worktree --staged one &&
+ test -z $(git status --porcelain --untracked-files=no)
+'
+
+test_expect_success 'restore with restore.defaultLocation set to both works as if --worktree --staged given' '
+ test_when_finished git reset --hard HEAD^ &&
+ test_when_finished git config --unset restore.defaultLocation &&
+ test_commit root-both-restore.defaultLocation &&
+ test_commit both-restore.defaultLocation one one &&
+ git config restore.defaultLocation both &&
+ > one &&
+
+ git restore one &&
+ test -z $(git status --porcelain --untracked-files=no) &&
+
+ > one &&
+ git add one &&
+ git restore --staged one &&
+ git status --porcelain --untracked-files=no | grep "^ M" &&
+
+ git add one &&
+ git restore one &&
+ test -z $(git status --porcelain --untracked-files=no) &&
+
+ > one &&
+ git add one &&
+ git restore --staged one &&
+ git status --porcelain --untracked-files=no | grep "^ M" &&
+
+ git restore --worktree one &&
+ test -z $(git status --porcelain --untracked-files=no) &&
+
+ > one &&
+ git add one &&
+ git restore --worktree --staged one &&
+ test -z $(git status --porcelain --untracked-files=no)
+'
+
+
test_done
base-commit: 725f57037d81e24eacfda6e59a19c60c0b4c8062
--
gitgitgadget
next reply other threads:[~2023-03-11 23:42 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-11 23:42 Hugo Sales via GitGitGadget [this message]
2023-03-12 21:32 ` [PATCH] Add `restore.defaultLocation` option Junio C Hamano
2023-03-13 18:02 ` Junio C Hamano
2023-03-13 23:11 ` Junio C Hamano
2023-03-14 23:51 ` Hugo Sales
2023-03-26 10:53 ` Hugo Sales
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.1467.git.git.1678578153640.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=hugo@hsal.es \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).