git 丢弃临时区域中的特定更改
git discard specifically changes in the staging area
在某些情况下,我想丢弃当前在暂存区中的所有文件,并且只丢弃当前在暂存区中的文件。本质上我想要的东西就像 进行提交然后立即丢弃刚刚进行的提交 .
现在在实践中我主要使用 git stash
来达到这个目的,请记住我实际上并不想要我藏起来的东西。
但是,stash
ing 和丢弃并不是一回事,stash
似乎捕获了所有被跟踪的文件,而不仅仅是当前在暂存区中的文件,如下面的脚本所示.
有没有办法完全丢弃(更改为)当前在暂存区中的文件?
#!/bin/bash
mkdir -p ./a
echo foo > ./a/foo
echo bar > ./a/bar
(
# add initial commit
cd ./a
git init
git add foo
git add bar
git commit --message='initial commit'
# change first line of foo and bar
ed ./foo <<'EOF'
s/$/ aaaaaa/
wq
EOF
ed ./bar <<'EOF'
s/$/ aaaaaaa/
wq
EOF
git add ./foo
git stash save
git status
)
当运行时,此脚本产生以下输出
$ bash gitrepo.sh
Initialized empty Git repository in ~/git/a/a/.git/
[master (root-commit) a8f0104] initial commit
2 files changed, 2 insertions(+)
create mode 100644 bar
create mode 100644 foo
4
11
4
12
Saved working directory and index state WIP on master: a8f0104 initial commit
HEAD is now at a8f0104 initial commit
我也尝试过用 git clean -f
和 git reset
代替 git stash save
的基本相同的脚本
git clean -f
似乎既没有放弃对 foo
的更改,也没有放弃对 bar
.
的更改
[master (root-commit) 0c10b47] initial commit
2 files changed, 2 insertions(+)
create mode 100644 bar
create mode 100644 foo
4
11
4
12
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: foo
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: bar
git reset
在这种特定情况下似乎只是从临时区域中删除 foo
。
[master (root-commit) 65fce7b] initial commit
2 files changed, 2 insertions(+)
create mode 100644 bar
create mode 100644 foo
4
11
4
12
Unstaged changes after reset:
M bar
M foo
目前我拥有的最佳解决方案是以下脚本,在我测试过的少数情况下它具有正确的行为。但是,它通过创建、提交然后删除一个由 UUID 命名的新分支来完成此行为。我更喜欢一种放弃临时区域中不那么迂回的更改的方法。
#!/bin/bash
branch="$(python -c 'import uuid; print(str(uuid.uuid4()))')"
git checkout -b "$branch"
git commit -m "commit for $branch"
git checkout -
git branch -D "$branch"
当使用 gitdiscard
(上面的脚本)时,测试脚本产生了正确的结果,foo 的更改被丢弃,但对 bar
的未暂存修改仍然存在。
[master (root-commit) e4e81d9] initial commit
2 files changed, 2 insertions(+)
create mode 100644 bar
create mode 100644 foo
4
11
4
12
M bar
M foo
Switched to a new branch 'abebe893-e579-4ecc-9422-6c99051d67f6'
[abebe893-e579-4ecc-9422-6c99051d67f6 05916d5] commit for abebe893-e579-4ecc-9422-6c99051d67f6
1 file changed, 1 insertion(+), 1 deletion(-)
M bar
Switched to branch 'master'
Deleted branch abebe893-e579-4ecc-9422-6c99051d67f6 (was 05916d5).
类似但不重复的问题的非详尽列表:
This question 不是重复,因为它指的是丢弃未跟踪的文件,而不是暂存区中的更改。
This question不是重复,因为它指的是直接清除整个工作,而不是丢弃暂存区中的更改。
This question 包括未跟踪的文件和未跟踪的目录,但不包括放弃对暂存区中文件的更改。
您可以考虑 --keep-index
标志 git stash
事实上,它确实与您的要求相反:它存储索引中的所有内容但。
您可以利用这一点,只存储未暂存的更改,然后重置索引和工作树,最后重新应用存储。
(我不确定您希望如何处理未跟踪的文件,但也有可能要记住存储标志 --include-untracked
。如果需要,请在第一个存储中使用它将它们包括在最终结果中)
git stash --keep-index [--include-untracked]
git reset --hard
git stash apply
首先,请记住当 git status
说:
nothing to commit, working tree clean
这并不意味着暂存区空。事实上,暂存区完全满了:每个文件在暂存区匹配当前(或HEAD
)中的每个文件犯罪。同时,暂存区中的每个文件 也 匹配工作树中的每个跟踪文件。
Is there a way to completely discard (changes to) exactly the files that are currently in the staging area?
考虑 git reset
、git checkout
和 - 在 Git 2.23(我还没有使用)git restore
:
git reset
命令有一种模式,它从当前提交复制一个文件,即 HEAD
,到索引/暂存区,而不触及全部工作树:
git重置--<em>文件</em>
仅当文件名 file
类似于分支名称或 git reset
选项时才需要 --
,例如,如果您有一个名为 master
的文件,并且您想让暂存版本与提交的版本匹配,git reset master
是错误的,但 git reset -- master
是正确的。
git reset HEAD
完全按照您的要求执行:它将 HEAD
提交中的每个文件复制到暂存区,因此不会暂存任何更改。
如果您还想更新文件的工作树副本,git checkout
的众多模式之一正是这样做的:
git 结帐 HEAD -- <em>file</em>
和以前一样,仅当文件名类似于 git checkout
选项时才需要 --
。例如,如果您想放弃对名为 --patch
的文件进行的暂存 and/or 未暂存更改,则 git checkout HEAD --patch
是错误的,但 git checkout HEAD -- --patch
是正确的。 (由于您必须在此处指定 HEAD
,因此 git checkout HEAD master
会抛出对名为 master
的文件的暂存和未暂存更改。但是,养成只使用的习惯更安全每次 --
。)
和以前一样,您可以检出当前提交中的每个每个文件,但是这次它需要使用检出一个folder(目录)名称导致 Git 递归地检查该文件夹的内容,因此:
git checkout HEAD -- .
可以解决问题,尽管您需要 .
来引用工作树的正确级别。
在 Git 2.23 中,新的 git restore
命令使您能够根据需要覆盖索引、工作树或两个副本。
记住,Git 始终为每个文件保留 三个 个活动副本。 提交的 HEAD
copy 无法更改——它在提交中并且提交无法更改——但可以使用 git reset
和 git checkout HEAD
访问它。索引副本——也称为暂存副本——可以随时通过以下方式覆盖:
- 从
HEAD
复制:现在没有任何更改,或者
- 从工作树复制:现在工作树中的任何内容都已上演。
工作树副本是一个普通的普通文件,所以你可以做任何你想做的事;但各种形式的 git checkout
将根据您的要求覆盖它。
在某些情况下,我想丢弃当前在暂存区中的所有文件,并且只丢弃当前在暂存区中的文件。本质上我想要的东西就像 进行提交然后立即丢弃刚刚进行的提交 .
现在在实践中我主要使用 git stash
来达到这个目的,请记住我实际上并不想要我藏起来的东西。
但是,stash
ing 和丢弃并不是一回事,stash
似乎捕获了所有被跟踪的文件,而不仅仅是当前在暂存区中的文件,如下面的脚本所示.
有没有办法完全丢弃(更改为)当前在暂存区中的文件?
#!/bin/bash
mkdir -p ./a
echo foo > ./a/foo
echo bar > ./a/bar
(
# add initial commit
cd ./a
git init
git add foo
git add bar
git commit --message='initial commit'
# change first line of foo and bar
ed ./foo <<'EOF'
s/$/ aaaaaa/
wq
EOF
ed ./bar <<'EOF'
s/$/ aaaaaaa/
wq
EOF
git add ./foo
git stash save
git status
)
当运行时,此脚本产生以下输出
$ bash gitrepo.sh
Initialized empty Git repository in ~/git/a/a/.git/
[master (root-commit) a8f0104] initial commit
2 files changed, 2 insertions(+)
create mode 100644 bar
create mode 100644 foo
4
11
4
12
Saved working directory and index state WIP on master: a8f0104 initial commit
HEAD is now at a8f0104 initial commit
我也尝试过用 git clean -f
和 git reset
代替 git stash save
git clean -f
似乎既没有放弃对 foo
的更改,也没有放弃对 bar
.
[master (root-commit) 0c10b47] initial commit
2 files changed, 2 insertions(+)
create mode 100644 bar
create mode 100644 foo
4
11
4
12
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: foo
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: bar
git reset
在这种特定情况下似乎只是从临时区域中删除 foo
。
[master (root-commit) 65fce7b] initial commit
2 files changed, 2 insertions(+)
create mode 100644 bar
create mode 100644 foo
4
11
4
12
Unstaged changes after reset:
M bar
M foo
目前我拥有的最佳解决方案是以下脚本,在我测试过的少数情况下它具有正确的行为。但是,它通过创建、提交然后删除一个由 UUID 命名的新分支来完成此行为。我更喜欢一种放弃临时区域中不那么迂回的更改的方法。
#!/bin/bash
branch="$(python -c 'import uuid; print(str(uuid.uuid4()))')"
git checkout -b "$branch"
git commit -m "commit for $branch"
git checkout -
git branch -D "$branch"
当使用 gitdiscard
(上面的脚本)时,测试脚本产生了正确的结果,foo 的更改被丢弃,但对 bar
的未暂存修改仍然存在。
[master (root-commit) e4e81d9] initial commit
2 files changed, 2 insertions(+)
create mode 100644 bar
create mode 100644 foo
4
11
4
12
M bar
M foo
Switched to a new branch 'abebe893-e579-4ecc-9422-6c99051d67f6'
[abebe893-e579-4ecc-9422-6c99051d67f6 05916d5] commit for abebe893-e579-4ecc-9422-6c99051d67f6
1 file changed, 1 insertion(+), 1 deletion(-)
M bar
Switched to branch 'master'
Deleted branch abebe893-e579-4ecc-9422-6c99051d67f6 (was 05916d5).
类似但不重复的问题的非详尽列表:
This question 不是重复,因为它指的是丢弃未跟踪的文件,而不是暂存区中的更改。
This question不是重复,因为它指的是直接清除整个工作,而不是丢弃暂存区中的更改。
This question 包括未跟踪的文件和未跟踪的目录,但不包括放弃对暂存区中文件的更改。
您可以考虑 --keep-index
标志 git stash
事实上,它确实与您的要求相反:它存储索引中的所有内容但。
您可以利用这一点,只存储未暂存的更改,然后重置索引和工作树,最后重新应用存储。
(我不确定您希望如何处理未跟踪的文件,但也有可能要记住存储标志 --include-untracked
。如果需要,请在第一个存储中使用它将它们包括在最终结果中)
git stash --keep-index [--include-untracked]
git reset --hard
git stash apply
首先,请记住当 git status
说:
nothing to commit, working tree clean
这并不意味着暂存区空。事实上,暂存区完全满了:每个文件在暂存区匹配当前(或HEAD
)中的每个文件犯罪。同时,暂存区中的每个文件 也 匹配工作树中的每个跟踪文件。
Is there a way to completely discard (changes to) exactly the files that are currently in the staging area?
考虑 git reset
、git checkout
和 - 在 Git 2.23(我还没有使用)git restore
:
git reset
命令有一种模式,它从当前提交复制一个文件,即HEAD
,到索引/暂存区,而不触及全部工作树:git重置--<em>文件</em>
仅当文件名
file
类似于分支名称或git reset
选项时才需要--
,例如,如果您有一个名为master
的文件,并且您想让暂存版本与提交的版本匹配,git reset master
是错误的,但git reset -- master
是正确的。git reset HEAD
完全按照您的要求执行:它将HEAD
提交中的每个文件复制到暂存区,因此不会暂存任何更改。如果您还想更新文件的工作树副本,
git checkout
的众多模式之一正是这样做的:git 结帐 HEAD -- <em>file</em>
和以前一样,仅当文件名类似于
git checkout
选项时才需要--
。例如,如果您想放弃对名为--patch
的文件进行的暂存 and/or 未暂存更改,则git checkout HEAD --patch
是错误的,但git checkout HEAD -- --patch
是正确的。 (由于您必须在此处指定HEAD
,因此git checkout HEAD master
会抛出对名为master
的文件的暂存和未暂存更改。但是,养成只使用的习惯更安全每次--
。)和以前一样,您可以检出当前提交中的每个每个文件,但是这次它需要使用检出一个folder(目录)名称导致 Git 递归地检查该文件夹的内容,因此:
git checkout HEAD -- .
可以解决问题,尽管您需要
.
来引用工作树的正确级别。
在 Git 2.23 中,新的 git restore
命令使您能够根据需要覆盖索引、工作树或两个副本。
记住,Git 始终为每个文件保留 三个 个活动副本。 提交的 HEAD
copy 无法更改——它在提交中并且提交无法更改——但可以使用 git reset
和 git checkout HEAD
访问它。索引副本——也称为暂存副本——可以随时通过以下方式覆盖:
- 从
HEAD
复制:现在没有任何更改,或者 - 从工作树复制:现在工作树中的任何内容都已上演。
工作树副本是一个普通的普通文件,所以你可以做任何你想做的事;但各种形式的 git checkout
将根据您的要求覆盖它。