运行 仅测试暂存文件:`git stash -k -u` 和 `git stash pop` 将引发部分暂存文件的冲突
Run tests only for staged files: `git stash -k -u` and `git stash pop` will raise conflicts on partial staged files
tl;博士
我想 运行 在提交前仅使用暂存文件进行测试:
git stash save -k -u
在测试前隐藏 unstaged/untracked files/changes
- 运行 使用暂存文件进行测试
git stash pop
在第 1 步恢复 changes/files。
问题是使用 git stash pop
会在部分暂存的文件上引发冲突。解决冲突将导致丢失部分 staged/unstaged 更改(您需要选择部分行重新上演)。
Update: If you want to know the shell script to run this procedure, please jump to the last section for more information.
注意:只有相邻的行(或足够接近)部分暂存才会导致此问题。例如,如果文件中有 6 个新行更改:
1 +| a (add to staged)
2 +| b (add to staged)
3 +| c (add to staged)
4 | d (keep unstaged)
5 | e (keep unstaged)
6 | f (keep unstaged)
现在使用git stash -k -u
然后git stash pop
会引起冲突。
演示问题
Git 为提交前的更改提供了三个阶段:staged
、unstaged
和 untracked
.
任何更改都将添加到 unstaged
。在提交之前,您可以选择一些行或文件并将它们添加到 staged
by git add
.
现在,在向 staged
添加了一些代码后,我想 运行 仅使用暂存文件进行测试以确保它们适合提交,因此我需要隐藏 unstaged
和 untracked
更改(新文件) git stash -k -u
并保持 staged
更改。
例如,我有 3 个文件更改:文件 A 已完全暂存,文件 B 已部分暂存(部分代码),文件 C 是未跟踪的新文件。
[staged]
file A
file B (only stage some of code)
[unstaged]
file B
[untracked]
file C (new file)
在 运行 宁 git stash -k -u
之后,所有 unstaged/untracked 更改都被隐藏。
[staged]
file A
file B (only stage some of code)
[unstaged/untracked]
<none, clean>
问题来了。在 运行ning 测试和 git stash pop
之后,它会引发文件 B 的冲突,因为它是部分暂存的。我确定我在存储和测试时没有更改文件 B。
我想知道如何与 git stash pop
自动合并而没有任何冲突,就像我隐藏它们之前一样。
我的工作流程
我觉得这是一个很普通的工作流程
development start
|
[make changes (unstaged)]
|
(pick changes to staged for commit by `git add`)<---|
| |
V (pick other changes to fulfill tests)
[partial staged/unstaged] |
| |
(stash unstaged changes by `git stash -k -u`) |
| |
(run tests only with staged files for commit) |
| |
(restore stashed files by `git stash pop`) |
| |
|------------<if test failed>-------------|
|
<if test success>
|
[commit staged files by `git commit`]
|
V
keep development or next commit
我需要一种方法来 stash pop
而不会丢失所有更改的 staged/unstaged 状态。保留暂存文件对于通过添加其他更改来提交或完成测试非常重要。
更新解决方案:一个 shell 脚本到 运行 程序
根据@torek 的回答,我写了一个 shell 脚本来 运行 测试,只有暂存文件:
#!/bin/sh -e
# stash all unstaged changes
# (-k: unstaged files; -u: new added files; -q: quite)
echo '--------------------------------------------------------------'
echo '---- Stash all unstaged/untracked files (git stash -k -u) ----'
echo '--------------------------------------------------------------'
BEFORE_STASH_HASH=$(git rev-parse refs/stash)
git stash -k -u -q
AFTER_STASH_HASH=$(git rev-parse refs/stash)
if [ "$BEFORE_STASH_HASH" == "$AFTER_STASH_HASH" ]; then
echo '\n\n---- Stash failed! Please check and retry. ----\n\n';
exit 1;
fi;
# run test only with staged files
echo '-------------------'
echo '---- Run tests ----'
echo '-------------------'
<run your tests here> || #### <=== replace your test command here
(echo '\n\n---- Tests failed! Please fix it before commit. ----\n\n')
# restore all stashed changes
#
echo '-----------------------------------------------------------'
echo '---- Restore all stashed files (git stash pop --index) ----'
echo '-----------------------------------------------------------'
git reset --hard -q &&
git clean -df -q &&
git stash pop --index -q ||
(echo '\n\n---- Restore failed! Please check and fix it. ----\n\n')
目前,这是@Paul 提供的解决方法。我写在这里,但我仍在寻找更好的解决方案。
这些是步骤:
- 使用
git stash -k -u
存储 unstaged/untracked 文件,但保留暂存文件以供提交。
- 运行 使用暂存文件进行测试。 如果失败,转第3步;如果通过,转到步骤4。
- 如果失败,您需要恢复 unstaged/untracked 文件并将新代码添加到暂存状态。这是我的问题的解决方法:
- 运行
git commit -m 'temp'
暂时将暂存文件存储在新提交中。
- 运行
git stash pop
恢复 unstaged/untracked 个文件。它仍然会引发提交(先前暂存)和未暂存之间相邻行更改的冲突。
- 运行
git checkout --theirs -- . && git reset
解决冲突,如果有的话,将unmerged
状态重置为unstaged
状态。因为之前暂存的文件现在已提交,git reset
不会影响它们。
- 运行
git reset HEAD^ --soft
将最新提交的文件回滚到 staged
状态。
- 现在您拥有与步骤 1 之前相同的文件状态 (staged/unstaged/untracked)。您可以添加从
unstaged
到 staged
的其他代码以满足测试要求。也许有一个 git 命令可以实现我正在寻找的上述步骤。
- 如果通过,只需
git commit
留言并开始下一次迭代开发。
另一种方法 是:(1) 先提交暂存文件,(2) 运行 测试最新的提交,(3) 修补提交,如果需要,通过 git commit --amend
直到通过测试。我不喜欢这种方法,因为任何对您工作的干扰都可能使您忘记继续修补提交以通过测试,并推送或发布错误的提交。
这不是一个完整的答案——更多信息请参见 How to recover from "git stash save --all"?——但是虽然这是一个有吸引力的过程,并且一旦 git stash
中的错误得到修复它就会起作用,但它有点危险今天
如果你已经修复了这个错误,或者不介意稍微危险地生活,:-) 你可以使用这个过程:
- 运行
git stash save -k -u
并确保它保存了一些东西(例如,比较 git rev-parse refs/stash
前后的结果)。
- 运行 你的测试。
git reset --hard && git clean -df
(可选,两者都包括 -q
)。只有当测试修改提交的文件时才需要 git reset --hard
,只有当测试创建未跟踪的文件时才需要 git clean
。
- 运行
git stash pop --index
。请注意,--index
在这里很关键。您也可以使用 -q
。
而不是 save
和 pop --index
,您可能想使用 create
和 apply --index
并将您的储物袋存储在不同的参考下(您操纵 and/or 完成后删除,以任何你喜欢的方式)。当然,如果你打算走到这一步,你可能想要编写自己的修改后的 git stash
脚本,首先避免当前的错误。
运行 测试有一种完全不同且在我看来更简单的方法:
- 创建一个空的临时目录。
- 将当前索引变成一棵树,然后将该树读入临时目录。 (或使用
git checkout-index
将索引提取到临时目录中。无论哪种情况,请注意环境变量 GIT_WORK_TREE
和 GIT_DIR
,或者 --git-dir
和 --work-tree
前端 git
命令的参数。)
- 运行 临时目录中的测试。
- 放弃临时目录。
这避免了 git stash save
错误,并且对步骤 2 稍作修改,让您可以测试任何修订。有两个明显的缺点:你需要一个地方来存储临时树,临时树不在工作树所在的地方。这些问题的严重程度取决于您的存储库和测试。
这个流程非常适合我,包括部分暂存的文件。我没有在步骤 2 中修改文件。
# 1. Stash all changes, then discard all unstaged changes
$ git stash --include-untracked --keep-index
# 2. Run tests, run linter, check types, etc. Don't modify files. Commit if desired.
# 3a. If no commit was made, restore to initial state
$ git stash pop
# 3b. If a commit was made, restore unstaged changes
$ git checkout stash -- . ; git stash pop ; git reset
~/.gitconfig
中有用的别名:
[alias]
stash-unstaged = stash --keep-index --include-untracked
restore-unstaged = "!git checkout stash -- . ; git stash pop ; git reset"
# Shortcuts
stun = stash-unstaged
restun = restore-unstaged
(请注意,别名 stash-unstaged
不太准确,因为存储还包括索引。但它很方便 shorthand。)
有了别名,命令就很简单了:
git stash-unstaged
运行 测试、linting 等
git stash pop
或 git restore-unstaged
,取决于是否进行了提交
tl;博士
我想 运行 在提交前仅使用暂存文件进行测试:
git stash save -k -u
在测试前隐藏 unstaged/untracked files/changes- 运行 使用暂存文件进行测试
git stash pop
在第 1 步恢复 changes/files。
问题是使用 git stash pop
会在部分暂存的文件上引发冲突。解决冲突将导致丢失部分 staged/unstaged 更改(您需要选择部分行重新上演)。
Update: If you want to know the shell script to run this procedure, please jump to the last section for more information.
注意:只有相邻的行(或足够接近)部分暂存才会导致此问题。例如,如果文件中有 6 个新行更改:
1 +| a (add to staged)
2 +| b (add to staged)
3 +| c (add to staged)
4 | d (keep unstaged)
5 | e (keep unstaged)
6 | f (keep unstaged)
现在使用git stash -k -u
然后git stash pop
会引起冲突。
演示问题
Git 为提交前的更改提供了三个阶段:staged
、unstaged
和 untracked
.
任何更改都将添加到 unstaged
。在提交之前,您可以选择一些行或文件并将它们添加到 staged
by git add
.
现在,在向 staged
添加了一些代码后,我想 运行 仅使用暂存文件进行测试以确保它们适合提交,因此我需要隐藏 unstaged
和 untracked
更改(新文件) git stash -k -u
并保持 staged
更改。
例如,我有 3 个文件更改:文件 A 已完全暂存,文件 B 已部分暂存(部分代码),文件 C 是未跟踪的新文件。
[staged]
file A
file B (only stage some of code)
[unstaged]
file B
[untracked]
file C (new file)
在 运行 宁 git stash -k -u
之后,所有 unstaged/untracked 更改都被隐藏。
[staged]
file A
file B (only stage some of code)
[unstaged/untracked]
<none, clean>
问题来了。在 运行ning 测试和 git stash pop
之后,它会引发文件 B 的冲突,因为它是部分暂存的。我确定我在存储和测试时没有更改文件 B。
我想知道如何与 git stash pop
自动合并而没有任何冲突,就像我隐藏它们之前一样。
我的工作流程
我觉得这是一个很普通的工作流程
development start
|
[make changes (unstaged)]
|
(pick changes to staged for commit by `git add`)<---|
| |
V (pick other changes to fulfill tests)
[partial staged/unstaged] |
| |
(stash unstaged changes by `git stash -k -u`) |
| |
(run tests only with staged files for commit) |
| |
(restore stashed files by `git stash pop`) |
| |
|------------<if test failed>-------------|
|
<if test success>
|
[commit staged files by `git commit`]
|
V
keep development or next commit
我需要一种方法来 stash pop
而不会丢失所有更改的 staged/unstaged 状态。保留暂存文件对于通过添加其他更改来提交或完成测试非常重要。
更新解决方案:一个 shell 脚本到 运行 程序
根据@torek 的回答,我写了一个 shell 脚本来 运行 测试,只有暂存文件:
#!/bin/sh -e
# stash all unstaged changes
# (-k: unstaged files; -u: new added files; -q: quite)
echo '--------------------------------------------------------------'
echo '---- Stash all unstaged/untracked files (git stash -k -u) ----'
echo '--------------------------------------------------------------'
BEFORE_STASH_HASH=$(git rev-parse refs/stash)
git stash -k -u -q
AFTER_STASH_HASH=$(git rev-parse refs/stash)
if [ "$BEFORE_STASH_HASH" == "$AFTER_STASH_HASH" ]; then
echo '\n\n---- Stash failed! Please check and retry. ----\n\n';
exit 1;
fi;
# run test only with staged files
echo '-------------------'
echo '---- Run tests ----'
echo '-------------------'
<run your tests here> || #### <=== replace your test command here
(echo '\n\n---- Tests failed! Please fix it before commit. ----\n\n')
# restore all stashed changes
#
echo '-----------------------------------------------------------'
echo '---- Restore all stashed files (git stash pop --index) ----'
echo '-----------------------------------------------------------'
git reset --hard -q &&
git clean -df -q &&
git stash pop --index -q ||
(echo '\n\n---- Restore failed! Please check and fix it. ----\n\n')
目前,这是@Paul 提供的解决方法。我写在这里,但我仍在寻找更好的解决方案。
这些是步骤:
- 使用
git stash -k -u
存储 unstaged/untracked 文件,但保留暂存文件以供提交。 - 运行 使用暂存文件进行测试。 如果失败,转第3步;如果通过,转到步骤4。
- 如果失败,您需要恢复 unstaged/untracked 文件并将新代码添加到暂存状态。这是我的问题的解决方法:
- 运行
git commit -m 'temp'
暂时将暂存文件存储在新提交中。 - 运行
git stash pop
恢复 unstaged/untracked 个文件。它仍然会引发提交(先前暂存)和未暂存之间相邻行更改的冲突。 - 运行
git checkout --theirs -- . && git reset
解决冲突,如果有的话,将unmerged
状态重置为unstaged
状态。因为之前暂存的文件现在已提交,git reset
不会影响它们。 - 运行
git reset HEAD^ --soft
将最新提交的文件回滚到staged
状态。 - 现在您拥有与步骤 1 之前相同的文件状态 (staged/unstaged/untracked)。您可以添加从
unstaged
到staged
的其他代码以满足测试要求。也许有一个 git 命令可以实现我正在寻找的上述步骤。
- 运行
- 如果通过,只需
git commit
留言并开始下一次迭代开发。
另一种方法 是:(1) 先提交暂存文件,(2) 运行 测试最新的提交,(3) 修补提交,如果需要,通过 git commit --amend
直到通过测试。我不喜欢这种方法,因为任何对您工作的干扰都可能使您忘记继续修补提交以通过测试,并推送或发布错误的提交。
这不是一个完整的答案——更多信息请参见 How to recover from "git stash save --all"?——但是虽然这是一个有吸引力的过程,并且一旦 git stash
中的错误得到修复它就会起作用,但它有点危险今天
如果你已经修复了这个错误,或者不介意稍微危险地生活,:-) 你可以使用这个过程:
- 运行
git stash save -k -u
并确保它保存了一些东西(例如,比较git rev-parse refs/stash
前后的结果)。 - 运行 你的测试。
git reset --hard && git clean -df
(可选,两者都包括-q
)。只有当测试修改提交的文件时才需要git reset --hard
,只有当测试创建未跟踪的文件时才需要git clean
。- 运行
git stash pop --index
。请注意,--index
在这里很关键。您也可以使用-q
。
而不是 save
和 pop --index
,您可能想使用 create
和 apply --index
并将您的储物袋存储在不同的参考下(您操纵 and/or 完成后删除,以任何你喜欢的方式)。当然,如果你打算走到这一步,你可能想要编写自己的修改后的 git stash
脚本,首先避免当前的错误。
运行 测试有一种完全不同且在我看来更简单的方法:
- 创建一个空的临时目录。
- 将当前索引变成一棵树,然后将该树读入临时目录。 (或使用
git checkout-index
将索引提取到临时目录中。无论哪种情况,请注意环境变量GIT_WORK_TREE
和GIT_DIR
,或者--git-dir
和--work-tree
前端git
命令的参数。) - 运行 临时目录中的测试。
- 放弃临时目录。
这避免了 git stash save
错误,并且对步骤 2 稍作修改,让您可以测试任何修订。有两个明显的缺点:你需要一个地方来存储临时树,临时树不在工作树所在的地方。这些问题的严重程度取决于您的存储库和测试。
这个流程非常适合我,包括部分暂存的文件。我没有在步骤 2 中修改文件。
# 1. Stash all changes, then discard all unstaged changes
$ git stash --include-untracked --keep-index
# 2. Run tests, run linter, check types, etc. Don't modify files. Commit if desired.
# 3a. If no commit was made, restore to initial state
$ git stash pop
# 3b. If a commit was made, restore unstaged changes
$ git checkout stash -- . ; git stash pop ; git reset
~/.gitconfig
中有用的别名:
[alias]
stash-unstaged = stash --keep-index --include-untracked
restore-unstaged = "!git checkout stash -- . ; git stash pop ; git reset"
# Shortcuts
stun = stash-unstaged
restun = restore-unstaged
(请注意,别名 stash-unstaged
不太准确,因为存储还包括索引。但它很方便 shorthand。)
有了别名,命令就很简单了:
git stash-unstaged
运行 测试、linting 等
git stash pop
或git restore-unstaged
,取决于是否进行了提交