我想使用这个工作流:
进行一些改变。 将未分阶段的更改保存到存储中。 用阶段中的东西做一些事情(构建、测试等)。 提交。 恢复未分阶段的更改。
有办法完成第二步吗?
例子:
git init
echo one >file
git add file
git commit
echo two >>file
git add file
echo three >>file
git stash push
test
git commit
git stash pop
我想使用这个工作流:
进行一些改变。 将未分阶段的更改保存到存储中。 用阶段中的东西做一些事情(构建、测试等)。 提交。 恢复未分阶段的更改。
有办法完成第二步吗?
例子:
git init
echo one >file
git add file
git commit
echo two >>file
git add file
echo three >>file
git stash push
test
git commit
git stash pop
当前回答
这是(在我看来)最好的解决方案,这完全符合OP的要求。它只存储未暂存的、被跟踪的文件——无需不必要的提交或使用——keep-index存储所有更改的文件
它列出了所有未分段的、跟踪的更改(git diff——name-only),将换行符转换为空格(| tr '\n' ' ' '),并使用git stash push存储所有这些文件:
git stash push $(git diff --name-only | tr '\n' ' ')
其他回答
我对Python程序如何预提交感兴趣。这是代码。 https://github.com/pre-commit/pre-commit/blob/3fe38dff05957f609cf7b97f471b35a8d9e0659a/pre_commit/staged_files_only.py#L50
它在功能上等同于:
git diff-index --ignore-submodules --binary --exit-code --no-color --no-ext-diff $(git write-tree) -- >stash.patch
git checkout -- .
# Do stuff now
git apply stash.patch && rm stash.patch
从Git 2.35+ (Q1 2022)开始,你现在可以在Git stash推送上使用——staging标志(man)来只stage你的索引的变化。
既然你的问题正好相反,我们有两个选择:
像这样反向操作:
git stash push --staged # Stash staged changes
git stash # Stash everything else
git stash pop stash@{1} # Restore staged changes stash
阶段性的更改是你想要保存的,而不是你想要保留的。现在你可以运行:
git stash push --staged
我从另一个S/O帖子的回答中得到了这个信息。
To my knowledge, it is currently impossible to save only unstaged changes in the working tree with git stash push, i.e. to save changes from the index state. This command saves all changes in the working tree (staged and unstaged changes), i.e. changes from the HEAD state, even with the option --keep-index which also sets the working tree state to the index state instead of the HEAD state (thereby creating conflicts when restoring the changes from the HEAD state with git stash pop). It would be very convenient if git stash push had an option -U|--unstaged for saving only unstaged changes (to me the option --keep-index is flawed), since it has already an option -S|--staged for saving only staged changes.
所以现在你必须模仿
git stash push --unstaged
git stash pop
使用临时文件:
git diff >unstaged
git restore .
git apply unstaged
rm unstaged
您的用例是在提交部分更改之前进行测试,它已经在参考文档中,但是使用了有缺陷的选项——keep-index,这会产生冲突。下面是带有模拟选项-U|——unstaging的版本:
git init
echo one >file
git add file
git commit
echo two >>file
git add file
echo three >>file
git diff >unstaged
git restore .
test
git commit
git apply unstaged
rm unstaged
想象状态
为了更好地理解存储,我认为在每一步查看工作树、索引和HEAD的状态是很重要的。让我们看看你的用例。
git init
working | index | HEAD |
---|
回显一个>文件
working | index | HEAD |
---|---|---|
one |
Git添加文件
working | index | HEAD |
---|---|---|
one | one |
git提交
working | index | HEAD |
---|---|---|
one | one | one |
回显两个>>文件
working | index | HEAD |
---|---|---|
one | one | one |
two |
Git添加文件
working | index | HEAD |
---|---|---|
one | one | one |
two | two |
回三>>文件
working | index | HEAD |
---|---|---|
one | one | one |
two | two | |
three |
愉快
去恢复.
working | index | HEAD |
---|---|---|
one | one | one |
two | two |
test
git提交
working | index | HEAD |
---|---|---|
one | one | one |
two | two | two |
Git应用unstaging
罗unstaged
working | index | HEAD |
---|---|---|
one | one | one |
two | two | two |
three |
这可以通过3个步骤完成:保存阶段性更改,保存所有其他内容,使用阶段性更改恢复索引。基本上就是:
git commit -m 'Save index'
git stash push -u -m 'Unstaged changes and untracked files'
git reset --soft HEAD^
这正是你想要的。
没有阶段性变化的隐藏
——keep-index / -k的问题
在Git中只存储工作树(非阶段性更改)比它应该做的要困难得多。接受的答案,以及其他一些答案,将存储非阶段的更改,并按照请求通过——keep-index离开阶段。
然而,不明显的是——keep-index还存储了分阶段的更改。阶段性的更改最终同时存在于阶段和存储中。这很少是人们想要的,因为对隐藏的任何临时更改都可能在稍后弹出隐藏时导致冲突。
别名解决方案
这个别名可以很好地执行工作副本更改:
stash-working = "!f() { \
git commit --quiet --no-verify -m \"temp for stash-working\" && \
git stash push \"$@\" && \
git reset --quiet --soft HEAD~1; }; f"
它临时提交分阶段的更改,从剩余的更改中创建一个隐藏(并允许额外的参数,如——include-untracked和——message作为别名参数传递),然后重置临时提交以获得分阶段的更改。
它类似于@Simon Knapp的答案,但有一些小的区别——它在所采取的临时操作上使用——quiet,它接受任意数量的参数用于stash推送,而不是硬编码-m,它确实在最终重置中添加——soft,以便索引保持它开始时的状态。它还在提交时使用——no-verify来避免来自预提交钩子(HT: @Granfalloner)对工作副本的更改。
关于只存储阶段性更改的相反问题(别名stash-index),请参阅此答案。