TL;DR
要查看文件名,请使用git ls-tree -r stash^3
;要查看其内容,请使用git show stash^3
.
Long
我怎样才能显示actual藏匿的内容,包括未跟踪的文件?
未跟踪的文件通常不在藏匿处。有一个例外,而您正在使用它,所以我稍后会讨论它。但显示这些文件很棘手。使用它们更加困难。这git stash
在我看来,前端需要做一些工作。
First, though, it's important to understand how Git works internally. A Git repository is primarily a pair of databases. One—the biggest one, almost always—holds commits and other Git objects. A smaller database holds names: branch names like master
, tag names like v2.1
, remote-tracking names like origin/master
, and so on. Branch names and tag names and the like are specific forms of the general purpose ref or reference. A ref holds a single Git hash ID, most commonly a commit hash ID.1
每个提交本身也可以保存一个或多个先前提交的哈希 ID。这些是parents提交的。对于正常(非存储)提交,这些通常形成一个很好的简单链:最后一个提交会记住倒数第二个提交作为其父级。倒数第二次提交会记住its父母——最后一次提交的祖父母——祖父母还记得另一个父母,依此类推。根据定义,具有两个父项的提交是合并提交。
因此,分支名称仅保存我们想说的提交的哈希 ID,这是该分支的最后一次提交。多个名称可以选择相同的哈希 ID,和/或哈希 ID 可以是可达的从某个分支开始,从其尖端提交并向后工作。因此,在 Git 中,提交通常位于多个分支上。
提交本身包含所有(跟踪的)文件的快照。 Git 通过将跟踪的文件写入 Git 来制作它们index然后使用git write-tree
,它将文件写入内部树对象,然后是git commit-tree
,它使用由以下代码编写的树写入提交对象git write-tree
。因此,所有提交都源自索引。并且,根据定义,索引中的任何文件都会被跟踪。所以这让我们有点困惑。
1Branch names and remote-tracking names are required to hold only commit hash IDs; tag names are more flexible.
藏品
The special ref refs/stash
, if it exists, points to one commit. That is the stash@{0}
commit. (Its reflog entries in stash@{1}
on up also point to one commit each.) So the stash, when it exists, consists of commits. These commits are on no branch:2 they're found through refs/stash
instead.
一个普通的储藏室有form合并提交,但不是相同的内容。什么git stash
所做的是使用非常低级别的进行两次提交git write-tree
and git commit-tree
方法如上所述。第一次此类提交,基于运行时索引中的内容git stash save
or git stash push
, 简单:git write-tree
已经只写入索引中的任何内容,因此这两个命令放在一起,使该索引提交,我称之为i
(以及git stash
文档调用I
).
第二次提交比较棘手,但本质上是什么git stash
确实是运行git add -u
(虽然没有实际使用git add -u
从而在各个版本中引入错误git stash
,其中一些在某些情况下会产生错误的工作树提交)。这会更新索引,以便它保存所有跟踪文件在工作树中的状态。然后git write-tree
其次是git commit-tree
为您的工作树制作一个很好的快照,当然减去任何未跟踪的文件。
Because git stash
使用低级命令,它可以使工作树提交——我称之为w
——与它选择的任何一对父母。它使这两个提交i
and HEAD
作为它的两个父母:
...--o--o <-- branch (HEAD)
|\
i-w
The i
提交看起来就像任何普通的提交,并且w
提交类似于合并。它实际上并不是合并,它只是添加到索引中的工作树的快照,但它的第一个父级是当前分支的提示提交,第二个父级是提交i
.
做好这个藏品后,git stash save
does a git reset --hard
,以便您的索引和工作树匹配HEAD
. The HEAD
其本身永远不会移动,未跟踪的文件不会保存且不受影响。
When you do a git stash save -u
or git stash save -a
, however, Git makes a third commit, which I call u
. This third commit uses an index that is cleared of all tracked files, and is then loaded with some or all of your untracked files, as if by git add --force
on specific file names.3 The set of files that go into this third commit depends on whether you used -u
or -a
: -u
enumerates untracked files that are not ignored, and -a
enumerates all untracked files, even if they are ignored. Git copies those files into the (well, an) index and makes this u
commit, with no parent at all, before it makes the final w
commit. Then it makes the w
commit with u
as its third parent:
...--o--o <-- branch (HEAD)
|\
i-w
/
u
Thus, w^1
是分支顶端的提交,w^2
是索引提交i
, and w^3
is the u
犯罪。w
仍然类似于合并提交(这次是章鱼合并),但其快照与任何两次提交存储相同。
做了一个u
犯罪,git stash save
or git stash push
now removes从您的工作树中的所有文件u
犯罪。如果某些文件在u
也被忽略,它们仍然被删除。
如果 Git 无法提取,应用三提交存储将会失败u
提交到您当前的工作树中。所以了解第三个内容绝对有用u
犯罪。但没有git stash ____
(用动词填空)显示是否提交u
甚至存在,更不用说里面有什么了。因此,我们必须求助于较低级别的 Git 命令。
特别是,自从u
is a 根提交, git show
将其与空树 https://stackoverflow.com/q/9765453/1256452。您可以使用git show --name-only
or git ls-tree -r
获取文件列表(如果您不需要完整的差异)。到name commit u
,我们可以命名任何存储提交——任何w
提交指向的对象refs/stash
或它的引用日志条目之一 - 并添加^3
后缀表示的意思第三父母。如果藏匿处只有w
and i
, the ^3
将失败:没有第三个父母,因此没有什么可显示的。
2You can, if you like, actually get them onto a branch, but the result is ... ugly at best.
3Internally, git stash
uses a temporary index instead of the real / main index, to make this easier. It does that for the w
commit too. While there is one special index, the index, that tracks your work-tree, you can create a temporary index at any time, put its path name into GIT_INDEX_FILE
, and use Git commands with that temporary index instead of using the distinguished index. That's handy for any command that needs to create a commit—which requires using the index—that doesn't want to disturb the index in the process.