当我这样做时git status
,有跟踪和未跟踪的文件。当天早些时候,我刚刚得知这git stash --include-untracked
会隐藏未跟踪的文件。当时它对我有用。所以我认为git stash --include-untracked
会保存跟踪和未跟踪文件的更改。但是当我 时git stash apply
,只剩下未跟踪文件的更改。跟踪文件的更改将丢失。
1 回答
这里有一些可疑的东西,但可能不是藏匿处本身
git stash --include-untracked
,可以git stash -u
简写为 stash 进行三个提交。
前两个与往常一样:一个保存运行时索引中的git stash
任何内容,另一个保存当时工作树中的任何内容(但仅跟踪文件)。换句话说,i
持有索引的提交持有 的结果git write-tree
,而w
提交持有(相当于)的结果git add -u && git write-tree
(尽管存储代码很难做到这一点,或者在过去的 shell 脚本存储中做到了)。
如果您在git stash
没有 --all
or的情况下运行,这就是存储所拥有的全部内容--include-untracked
:它将具有i
(index state) 和w
(work-tree state) 的两个提交,这两个提交都将当前提交C
作为它们的第一个父级。Commit作为w
它i
的第二个父节点:
...--o--o--C <-- HEAD
|\
i-w <-- stash
但是,如果你添加or -u
,-a
你会得到一个三提交存储:提交w
获取第三个父级,我们可以调用的提交u
,它保存未跟踪的文件。这个第三个父级没有自己的父级(是一个孤儿/根提交),所以现在的绘图是:
...--o--o--C <-- HEAD
|\
i-w <-- stash
/
u
这个新提交的有趣之处以及它在工作树中的影响是:*提交只u
包含未跟踪的文件。**
请记住,提交是所有(跟踪的)文件的完整快照。提交u
是通过——在一个临时索引中——<em>丢弃所有跟踪的文件,而是跟踪一些或所有未跟踪的文件。此步骤要么仅添加未跟踪但未忽略的文件 ( git stash -u
),要么添加所有文件 ( git stash -a
)。然后 Git 写入 commit u
,git write-tree
用来将临时索引变成树放入 commit u
,这样 commit 就只u
包含选中的文件。
现在这些选定的文件在 commit 中u
,git stash
将它们从 work-tree 中删除。在实践中,它过去只是git clean
使用适当的选项运行。新的更高级的 C 编码git stash
仍然具有相同的功能(但是,人们可能希望,错误更少;见下文)。
这类似于它对i
and/or中的文件所做的事情w
:它有效地执行 a git reset --hard
,以便工作树的跟踪文件与HEAD
提交匹配。(也就是说,除非您使用--keep-index
,否则它会执行此操作,在这种情况下,它会重置文件以匹配i
提交。)此时git reset
对未跟踪的文件没有影响,这些文件超出了 的范围git reset
,并且对当前分支没有影响,因为重置故意将其保持在HEAD
.
u
但是,在 commit 中隐藏了一些未跟踪的文件,git stash
然后从工作树中删除这些文件。这在以后很重要(也许也很重要)。
注意:与 pathspecs结合存在一个错误,可能会影响所有内容,但尤其会影响使用orgit stash push
制作的存储变体,其中某些版本的 Git 删除了太多文件。也就是说,您可能只是文件的一部分,但 Git 会或所有文件,或太多文件。(我相信这些今天都已修复,但总的来说,我根本不建议使用,尤其是不要使用花哨的 pathspec 变体。删除实际上没有隐藏的未跟踪文件是特别令人震惊的行为,某些版本的 Git 确实如此那!)-u
-a
git stash
git reset --hard
git clean
git stash
您描述了一个apply
时间问题,但可能不是通常的问题
这是你说的:
我认为
git stash --include-untracked
会保存已跟踪和未跟踪文件的更改。
与往常一样,Git 不会保存更改,它会保存快照。
但是当我“git stash apply”时,只剩下未跟踪文件的更改。跟踪文件的更改将丢失。
应用正常(无未跟踪文件)存储以两种方式之一完成,具体取决于您是否使用该--index
标志。without 的变体--index
更容易解释,因为它实际上只是忽略了i
提交。(带有--index
标志的变体首先git apply --index
在差异上使用,如果失败,建议您尝试不使用--index
。如果您想要的效果--index
,这是一个糟糕的建议,您应该忽略它。但是,对于这个答案,让我们忽略该--index
选项完全。)
注意:这不是--keep-index
标志,而是--index
标志。该--keep-index
标志仅在创建存储时适用。该--index
标志在应用存储时应用。
为了应用w
提交,Gitgit merge-recursive
直接运行。作为用户,这不是你应该做的事情,什么时候做git stash
,这也不是那么明智,但这就是它的作用。效果很像 running git merge
,除了如果您在索引和/或工作树中有未提交的更改,则可能无法以任何自动方式返回此状态。
如果你从一个“干净的”索引和工作树开始——也就是说,如果git status
说——这个合并操作在很多方面几乎与常规的ornothing to commit, working tree clean
完全相同。(请注意,两者都要求事情是干净的,至少在默认情况下是这样。)合并操作在合并基础设置为 commit 的父级的情况下运行,当前或提交照常是当前提交,另一个或提交是提交.git merge
git cherry-pick
git merge
git cherry-pick
w
--ours
--theirs
w
也就是说,假设您的提交图现在看起来像这样:
o--o--A--B <-- branch (HEAD)
/
...--o--o--C
|\
i-w <-- stash
/
u
这样你就可以提交了B
。应用存储的合并操作执行三向合并,作为C
合并基础和提交,当前提交/工作树作为提交。Git diffs vs看看我们改变了什么,vs看看他们改变了什么,并结合了两组差异。w
--theirs
--ours
C
B
C
w
这就是 merge into 的B
运行方式,前提是 Git 可以首先取消存储 commit u
。此时通常的问题是 Git不能un-stash u
。
请记住,提交u
包含完全(且仅)您进行存储时存在的未跟踪文件,然后 Git 使用git clean
(和适当的选项)删除。 这些文件必须仍然不存在于工作树中。 如果它们不缺席,git stash apply
将无法从中提取文件u
并且不会继续。
由于未跟踪的文件是未跟踪的,因此很难知道它们是否已更改
但是当我“git stash apply”时,只剩下未跟踪文件的更改。跟踪文件的更改将丢失。
您谈论未跟踪文件的更改。
Git 当然不存储更改,因此您无法以这种方式找到它们。如果文件未被跟踪,它们现在也不在索引中。所以:你怎么知道他们改变了? 您需要一些其他文件集来比较它们。
提取提交的步骤u
应该是全有或全无:它应该提取所有u
文件,或者不提取。如果它确实提取了所有u
文件,git stash apply
则应该继续尝试合并,有点像git cherry-pick -n
(除了cherry-pick 也写入索引),w
在存储中提交。这应该会在您的工作树中留下提取的u
文件和合并w
的 -vs-C
更改。
如果C
-vs-work-tree 与C
-vs-之间存在冲突w
,您应该在工作树中存在冲突标记,并且您的索引应该像往常一样扩展以进行冲突合并。
如果您可以为您的问题制作一个复制器,那可能会在这里提供大量的清晰度。