2

当我这样做时git status,有跟踪和未跟踪的文件。当天早些时候,我刚刚得知这git stash --include-untracked会隐藏未跟踪的文件。当时它对我有用。所以我认为git stash --include-untracked会保存跟踪和未跟踪文件的更改。但是当我 时git stash apply,只剩下未跟踪文件的更改。跟踪文件的更改将丢失。

4

1 回答 1

2

这里有一些可疑的东西,但可能不是藏匿处本身

git stash --include-untracked,可以git stash -u简写为 stash 进行三个提交。

前两个与往常一样:一个保存运行时索引中的git stash任何内容,另一个保存当时工作树中的任何内容(但仅跟踪文件)。换句话说,i持有索引的提交持有 的结果git write-tree,而w提交持有(相当于)的结果git add -u && git write-tree(尽管存储代码很难做到这一点,或者在过去的 shell 脚本存储中做到了)。

如果您在git stash 没有 --allor的情况下运行,这就是存储所拥有的全部内容--include-untracked:它将具有i(index state) 和w(work-tree state) 的两个提交,这两个提交都将当前提交C作为它们的第一个父级。Commit作为wi的第二个父节点:

...--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 ugit write-tree用来将临时索引变成树放入 commit u,这样 commit 就u包含选中的文件。

现在这些选定的文件在 commit 中ugit stash 将它们从 work-tree 中删除。在实践中,它过去只是git clean使用适当的选项运行。新的更高级的 C 编码git stash仍然具有相同的功能(但是,人们可能希望,错误更少;见下文)。

这类似于它对iand/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-agit stashgit reset --hardgit 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 mergegit cherry-pickgit mergegit cherry-pick w--ours--theirsw

也就是说,假设您的提交图现在看起来像这样:

       o--o--A--B   <-- branch (HEAD)
      /
...--o--o--C
           |\
           i-w   <-- stash
            /
           u

这样你就可以提交了B。应用存储的合并操作执行三向合并,作为C合并基础和提交,当前提交/工作树作为提交。Git diffs vs看看我们改变了什么,vs看看他们改变了什么,并结合了两组差异。w--theirs--oursCBCw

这就是 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,您应该在工作树中存在冲突标记,并且您的索引应该像往常一样扩展以进行冲突合并。

如果您可以为您的问题制作一个复制器,那可能会在这里提供大量的清晰度。

于 2019-10-25T21:25:51.423 回答