试图弄清楚隐藏的工作方式。我有以下“ git status”
On branch master
Your branch is up-to-date with 'origin/master'.
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: ../../../root/index.tt
Untracked files:
(use "git add <file>..." to include in what will be committed)
Coupons.pm
../../../root/coupons/
no changes added to commit (use "git add" and/or "git commit -a")
当我执行“ git stash save -a”时,发出命令“ git stash show -p”只会显示以下内容,看不到上面的目录或文件“ Coupons.pm”,但是如果我应用了存储,它将返回。
index 629342697e..ecd82eb69f 100644
--- a/View/Web/OmniHUB2/root/index.tt
+++ b/View/Web/SomeSite/root/index.tt
@@ -120,6 +120,9 @@
<a class="btn btn-primary btn-block" href="/someinterface">SOME Interface</a>
</div>
[% END %]
+ <div class="col-xs-12 col-sm-6">
+ <a class="btn btn-primary btn-block" href="/coupons">Coupons</a>
+ </div>
</div>
</div>
lines 1-14/14 (END)
答案 0 :(得分:3)
您可以使用git stash list
查看所有现有的存储。你会得到这样的东西:
stash@{0}: WIP on branch-1: 1af3a3456 Add config file
stash@{1}: WIP on branch-1: f8325f42d Update some function
stash@{2}: WIP on branch-2: bae22df24 Merge branch 'branch-3' of
您可以使用git stash show -p stash@{2}
查看特定存储的差异。
答案 1 :(得分:2)
git stash
的工作原理非常简单。是后果变得很复杂。在这种情况下,您的未跟踪文件处于额外提交状态,git stash show
不会显示出来。
要显示此额外提交中的内容,可以使用:
git show stash^3
将显示添加的每个此类文件。
git stash
的作用是进行两次提交(有时是三次提交,而您正在使用第三种提交模式),这两个提交都不在任何分支上。所需的两次提交将保存 index 的内容和 work-tree 的内容。第三次提交(如果存在)保存未跟踪的文件(忽略的文件除外)或未跟踪的文件(不包含其他文件)。
因此, 中的提交是两个(或三个)快照,以及每个提交随附的其余元数据,即两个(或三个)元数据块。除了一个例外,这些块中的元数据并不是特别有用,并且可以被忽略。
这里也值得一提git status
的工作原理,因为它们是相关的。您需要了解以下事实:Git提供了称为 index , staging area 或(通常是现在) cache < / em>,具体取决于Git的哪个部分正在执行调用。由于这主要是关于git stash
的,因此我在这里只说git status
进行两次比较:将HEAD
与索引进行比较以查找其调用的内容准备提交的文件,然后分别对索引和工作树进行比较,以查找其所谓的未准备提交的文件。
您可能已经知道,每个Git提交都保存着所有源文件的完整快照(嗯,提交时跟踪的所有文件)。您可能还知道提交包含元数据:(用户名和电子邮件地址),创建时间(日期和时间戳),原因(日志消息)以及提交的哈希ID的原因。提交的 parent:在此提交之前的提交。每个提交都具有自己的唯一哈希ID,该ID与其他提交的ID不同,但是计算方式使宇宙中的每个Git都同意那个提交得到那个哈希ID。
因为每个提交都记住其前身的哈希ID,所以我们只需要知道任何提交链中 last 提交的哈希ID:
A <-B <-C (need C's hash ID)
我们让Git读取提交C
来找到B
的哈希ID,然后读取B
来找到A
的哈希ID。像master
这样的分支名称仅保存该系列中 last 提交的哈希ID。
要进行 new 提交,Git只需立即保存索引 中的内容,添加您的姓名和电子邮件,依此类推,设置 parent < / em>到 current 提交,并将所有内容写为新提交,这将生成新提交的新的唯一哈希ID。我们将新提交称为D
,并且D
指向C
,因此我们将其绘制为:
A--B--C <-- branch
\
D
要记住D
已添加到分支branch
中,Git现在将D
的新哈希ID填充到 name branch
中,给我们:
A--B--C--D <-- branch
由于各种原因,包括节省大量空间,提交中的文件采用特殊的只读,仅Git,冻结,压缩形式。只有Git可以使用它,没有人甚至Git都不能 change 其中的任何一个。尽管这不是Git的正式术语,但我还是称这些文件为“冻干”。
您当然需要将文件解冻并重新水化。这些文件进入您的工作树,您可以在其中看到它们并对其进行处理。因此,每个文件肯定有两个副本:在当前提交中冻干的一个副本,以及工作树中的可用版本。
Git将索引/暂存区域添加为着陆点或启动点之间的部分:索引中也有文件的冻干副本。不过,与提交的版本不同,您可以随时替换一个。这就是git add
的作用:它将工作树副本冻干,并将其写入索引,以替换先前的索引副本,或者在索引中创建文件。以前没有。
Git保存 index 中的内容而不是 work-tree 中的内容的事实是为什么我们必须如此频繁地运行git add
的原因。它也使git commit
变得非常快:无需扫描整个工作树,无需重新压缩每个文件以查看其是否已更改。 git add
删除重要文件时,您已经对其进行了重新压缩。冻干的索引副本已采用正确的格式以进行新的提交。 Git可以将它们打包并完成。
跟踪文件的定义非常简单:它是现在索引为 的任何文件名。由于git commit
保存了索引中的内容,因此文件的跟踪版本就是新提交中的内容。现在工作树中的内容无关紧要:文件只必须在索引中即可。不管它有什么形式, 就是要提交的内容。
因此,未跟踪文件的定义也非常简单:它是名称在工作树中但不在索引中的任何文件。 (如果它既不在工作树的索引 nor 中,则根本不存在。有多少个不存在的文件不在索引或工作树中?现在?:-)实际上在大多数系统上都有一个可数的答案,但是数量如此之多,不值得过多考虑:例如,在Linux上约为254 255 。)未被跟踪的文件可以被简单地取消跟踪,在这种情况下,Git有时会抱怨该文件,也可以被取消跟踪并且被忽略来关闭投诉。
(没有被跟踪但被忽略的文件:如果文件被跟踪,它就不会被定义忽略。可以在文件中的 中设置一些特殊状态位索引,但我们不要在这里讨论。)
git stash
的提交在the git stash
documentation中间,他们提到I
和W
提交,我通常将其称为i
和w
提交。 stash命令的工作是在不更改当前分支的情况下进行这些提交,然后更新refs/stash
(而不是分支名称)以保存其哈希ID之一。这足以找到两个提交。
隐藏代码几乎以通常的方式提交i
。正如我们在上面看到的,git commit
通过包裹冻干的文件,设置元数据(以父级为当前提交),写出提交并将新提交的哈希ID写入当前分支来进行提交。名称。如果我们只是停止git commit
进行 last 步骤,然后将哈希ID保存在其他位置,那么我们将得到所需的信息:
A--B--C--D <-- branch
\
i (git-stash will save i's hash ID somewhere)
现在git stash
需要以某种方式保存当前的工作树,如果您要保存它,还需要保存第三次提交。现在让我们假设我们不需要第三次提交,只需将w
提交一次即可。我们想要进行设置,以便w
保留所有被跟踪的工作树文件的副本。为此,存储代码将创建第二个临时索引,并将所有文件的所有工作树版本复制到其中。它使用一些棘手的代码来避免不必要的重新冷冻干燥,但是原则上它只是:
for (every file $f in the real index): copy $f into temporary index
然后,隐藏代码使用w
和作为其(两个)父级,通过此临时索引进行i
提交:
A--B--C--D <-- branch
|\
i-w (git-stash now has w's commit hash too)
然后,git stash
仅将w
添加到refs/stash
,如果已经存在refs/stash
,则使用推式操作;如果不存在,则创建refs/stash
:< / p>
A--B--C--D <-- branch
|\
i-w <-- refs/stash
稍后,我们将介绍git stash
的最后几位。
如果您选择进行第三次提交(我将u
称为“未跟踪”文件),则隐藏代码会在写入之前在 中写出第三次提交退出w
提交。为了进行提交,git stash
列出了所有未跟踪的文件,包括(-a
/ --all
)或排除(-u
/ --include-untracked
)被忽略的子集未跟踪的文件。然后,它会执行类似于w
提交的技巧:它会创建一个临时索引,然后将列出的每个文件复制到该临时索引中,并从中进行u
提交。
stash
代码为u
提交 no 父级。这个u
提交只是悬挂在那里,没有附加任何东西:
A--B--C--D <-- branch
|
i
u
然后,在同时完成i
和u
提交的情况下,git stash
返回到w
提交的状态,使用以前的临时索引并复制工作-根据它们在实/常规索引中的存在将树文件放入其中。然后,当它进行w
提交时,它给w
一个第三父级,即刚刚进行的u
提交:
A--B--C--D <-- branch
|\
i-w <-- refs/stash
/
u
,然后像以前一样将w
提交的哈希ID写入refs/stash
。
git stash
已经进行了这两次或三次提交,现在必须清理索引和工作树。此处的默认设置只是运行git reset --hard
,它将所有冻结的文件从当前提交复制到索引,然后再复制到工作树。使用-u
或-a
进行第三次提交时,git stash
也使用git clean
或等效的命令来删除它在该第三次提交中放置的任何文件。
(使用--keep-index
选项,git stash
重置工作树以匹配索引,索引不保留它,以便索引匹配i
提交。{{ 1}}或-a
保持不变。)
为了正确地还原(-u
或pop
)存储,Git需要索引和/或工作树中的文件是“干净的”。对于两次提交的存储,Git并没有提出严格的要求:它只是尝试将存储合并到当前工作树中。后果可能是一团糟,在某些情况下很难或不可能扭转它。这意味着apply
如果git stash apply
说除了什么都不做,可以清除树的消息,git stash pop
或git status
通常是不明智的;但这是您的选择。 >
但是,对于三个提交的存储,Git更加小心。奇怪的是,这可能会令人沮丧。特别是,Git尝试不破坏存在的,未跟踪的任何工作树文件,并通过从u
提交中检出文件来覆盖它们。本质上,这意味着您通常必须运行git clean
只是为了检查由-a
或-u
制成的存储。
当您成功提取这样的存储时,Git将具有:
u
个提交文件提取到工作树中(这些文件现在应该都是新的,并且已被取消跟踪,并且根据与那时相比.gitignore
文件的状态,可能类似地被忽略了) /不像以前一样被忽略)。w
提交文件与您现有的工作树合并。--index
,请使用i
将与父级进行比较的git apply --cached
应用于您现有的索引。其中两个步骤与所有隐藏相同。
如果存储附加到提交D
,并且索引和工作树是原始的且匹配D
,则git stash apply --index
将始终成功(除非存在任何git stash
错误那是)。因此:
git checkout $(git rev-parse refs/stash^1)
git reset --hard
git stash apply --index
将完全应用两次提交的存储并完全从git stash
恢复状态,但是对于三个提交的存储,必须使用git clean
或{添加一个-df
命令{1}}删除-dfx
文件。请注意,u
和git reset --hard
都可能破坏未保存在Git中任何地方的工作,因此,最好确保将这些工作保存在某个地方(也许很奇怪,使用{{1} } :-))。