`git stash show -p stash @ {N}`和`git show stash @ {N}`之间的区别? [英] Difference between `git stash show -p stash@{N}` and `git show stash@{N}`?

查看:155
本文介绍了`git stash show -p stash @ {N}`和`git show stash @ {N}`之间的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为它们应该基本相同,但是当我尝试

I thought they should be basically the same, but when I tried

$ git stash show -p stash@{N}

$ git show stash@{N}

后者显示了一些其他提交信息,但是实际的差异要短得多. (前者显示了大约十二个文件,而后者仅显示了一个.)

the latter shows some additional commit information, but the actual diff was much, much shorter. (The former shows about a dozen files, but the latter only one.)

那么,两者之间到底有什么区别,为什么又有区别呢?

So, what exactly is the difference between the two and why are they different?

我还可以依靠git diff stash@{M} stash@{N}之类的东西做对吗?

Can I also rely on things like git diff stash@{M} stash@{N} to be correct?

推荐答案

储物袋

git stash所保存的东西就是我所说的储物袋" .它由两个 1 单独的提交组成:索引"提交(登台区域)和工作树"提交.工作树提交是一种有趣的合并提交.

Stash bags

The thing saved by git stash is what I have taken to calling a "stash bag". It consists of two1 separate commits: the "index" commit (the staging area), and the "work tree" commit. The work-tree commit is a funny kind of merge commit.

让我在这里再次绘制(请参阅参考答案以获取更长的版本),只是为了正确说明它.为了简单起见,我们假设您有一个小型仓库,其中只有一个分支和三个提交,分别是AC.您位于一个分支上,进行了一些更改,然后运行git stash save(或仅运行git stash).这就是您得到的:

Let me draw this again here (see the referenced answer for a much longer version), just to illustrate it properly. Let's assume for simplicity that you have a small repo with just one branch and three commits on it, A through C. You're on the one branch and make a few changes and then run git stash save (or just plain git stash). This is what you get:

A - B - C     <-- HEAD=master
        |\
        i-w   <-- the "stash"

现在您可以建立(或切换到)另一个分支,但是为了说明起见,我们只说您将存储区保留在那里并在master上进行更多的常规"提交:

Now you might make (or switch to) another branch, but for illustration, let's just say you leave that stash there and make more "regular" commits on master:

A - B - C - D - E    <-- HEAD=master
        |\
        i-w   <-- stash

此处的要点是,存储袋"(即i ndex和w ork-tree提交对)仍与以前的提交相同.提交不能更改,对于存储袋提交也是如此.

The point here is that the "stash-bag", the pair of index and work-tree commits, is still hung off the same commit as it was before. Commits cannot be changed, and this is true of stash-bag commits too.

但是现在您可以通过进行一些更改(仍在master上)并再次运行git stash save来创建 new 存储区.

But now you make a new stash by making some changes (while still on master) and running git stash save again.

旧的储物袋会怎样?现在,参考名称" 2 stash指向 new 储物袋.但是旧的存储袋提交仍在那儿.他们现在只需要一个"reflog"样式名称,stash@{1}. 3

What happens to the old stash-bag? The "reference name"2 stash, now points to the new stash-bag. But the old stash-bag commits are still in there. They just now require a "reflog" style name, stash@{1}.3

无论如何,您现在拥有的是这个

Anyway, what you have now is this:

A - B - C - D - E     <-- HEAD=master
        |\      |\
        i-w     i-w   <-- stash
          .
           -------------- stash@{1}

(当您使用git stash drop时,隐藏脚本仅操作stash ref的reflog来删除所放下的存储袋的ID.这就是为什么所有较高"的存储袋都被重新编号的原因.实际的存储-袋子本身是在下一个git gc上收集的垃圾.)

(When you use git stash drop, the stash script simply manipulates the reflog for the stash ref to delete the ID of the dropped stash-bag. That's why all the "higher" ones get renumbered. The actual stash-bag itself is garbage collected on the next git gc.)

接下来的那一点是了解正在发生的事情的关键.

This next bit is a key to understanding what's going on.

每个提交都有一个真实名称",这是您看到的难看的SHA-1哈希值,例如676699a0e0cdfd97521f3524c763222f1c30a094.你可以这样写.它总是意味着相同的提交.提交永远都不能更改,这是提交全部内容的加密哈希,因此,如果完全存在该特定提交,则该值始终是其名称.

Each commit has a "true name" that is the big ugly SHA-1 hash you see, values like 676699a0e0cdfd97521f3524c763222f1c30a094. You can write that. It always means the same commit. Commits can never be changed, and that's a cryptographic hash of the entire contents of the commit, so if that particular commit exists at all, that value is always its name.

不过,这对人们来说不是一个好名字.因此,我们有别名:诸如分支和标记名称之类的东西,以及诸如HEADHEAD~2之类的相对名称,以及诸如HEAD@{yesterday}master@{1}之类的引用日志样式名称. (有一个命令git rev-parse,它将这样的名称字符串转换为哈希值.尝试:运行git rev-parse HEADgit rev-parse stash等.git中的大多数操作都使用git rev-parse或它的老兄git rev-list,将名称转换为SHA-1值.)

It's not a good name for people, though. So we have aliases: things like branch and tag names, and relative names like HEAD and HEAD~2, and reflog-style names like HEAD@{yesterday} or master@{1}. (There's a command, git rev-parse, that turns name strings like this into hash values. Try it: run git rev-parse HEAD, git rev-parse stash, and so on. Most things in git use either git rev-parse or its big brother that does a lot more, git rev-list, to turn names into the SHA-1 values.)

(有关如何命名修订的完整说明,请参见 gitrevisions .Git不仅将SHA-1用作提交,而且这里只考虑提交.)

(For a complete description of how to name a revision, see gitrevisions. Git uses SHA-1s for more than just commits, too, but here let's just think about commits.)

好的,最后,我们可以进入您的git showgit stash showgit diff等.首先解决git stash show,因为这是应该与隐藏一起使用的那个.此外,git stash子命令将验证您命名的提交(或者,如果您未命名,则是通过stash引用找到的提交),看起来像"一个存储,即是这些有趣的合并之一提交.

OK, finally, we can get to your git show vs git stash show, and git diff and so on. Let's tackle git stash show first as that's the one you are supposed to use with stashes. Moreover, the git stash sub-commands will verify that the commit you name—or, if you name no commit, the one found via the stash reference—"looks like" a stash, i.e., is one of these funny merge commits.

如果运行git stash show -p,则git会显示差异(-p atch).但是它到底显示了什么?

If you run git stash show -p, git shows you a diff (-patch). But what exactly is it showing?

回到带有储物袋的图表.每个存储袋都挂在特定的 提交中.上方,主要"存储区现在挂在提交E上,而stash@{1}早期存储区则挂在C上.

Go back to the diagram with the stash-bags. Each stash-bag is hung off a specific commit. Above, the "main" stash is now hanging from commit E, and the stash@{1} earlier stash is hanging from C.

git stash show -p所做的是将存储区的工作树提交w与存储区挂起的提交进行比较. 4

What git stash show -p does is compare that stash's work-tree commit, the w, against the commit from which the stash hangs.4

您当然可以自己做.假设您要比较stash中的w(挂起提交E)与提交E(可以用分支名称master命名)进行比较.这样就可以运行:git diff master stash.这里的名称stash表示(当前)隐藏提交w,而master表示提交E,因此这产生与git stash show -p stash完全相同的补丁. (并且,如果您想将stash@{1}中的w与提交C进行比较,则只需运行git diff,以便您命名这两个提交.当然,仅git stash show -p stash@{1}会更容易.) 5

You can of course do this yourself. Let's say you want to compare the w in stash, which hangs off commit E, against commit E, which can be named by the branch-name master. So you can run: git diff master stash. Here the name stash refers to the (current) stash commit w, and master refers to commit E, so this produces the exact same patch as git stash show -p stash. (And, if you want to compare the w in stash@{1} against commit C, you just need to run git diff such that you name those two commits. Of course it's easier to just git stash show -p stash@{1}.)5

那普通的git show呢?这有点复杂. git show很高兴显示提交,您为它提供了stash引用(stash本身或reflog变体之一).这是一个有效的提交标识符,它解析为其中一个存储袋中的w工作树提交之一.但是,当git show看到 merge 提交时,其行为会有所不同.如文档所述:

What about plain git show? This is a little more complicated. git show is happy to show a commit, and you gave it a stash reference (either stash itself, or one of the reflog variants). That's a valid commit identifier, and it resolves to one of the w work-tree commits in one of the stash-bags. But git show acts differently when it sees a merge commit. As the documentation says:

它还以git diff-tree --cc产生的特殊格式显示合并提交.

It also presents the merge commit in a special format as produced by git diff-tree --cc.

因此,git show stash@{1}向您显示一个组合差异",假定提交w是提交Ci的正常合并,从而生成w.毕竟,这不是正常的合并,尽管合并的差异可能实际上很有用,但前提是您知道要查看的内容.请阅读git diff-tree下的--cc文档以详细了解其工作原理,但我会注意到--cc暗含了-c,其中包括以下内容:

So git show stash@{1} shows you a "combined diff", assuming that commit w is a normal merge of commits C and i, producing w. It's not a normal merge after all, although a combined diff may actually be useful, provided you know what you're looking at. Read the --cc documentation under git diff-tree to see how that works in detail, but I'll note that --cc implies -c which includes this bit:

...仅列出从所有父级修改而来的文件.

... lists only files which were modified from all parents.

对于stash,如果在运行git stash之前已具有git add -ed个文件,则i -vs- w差异为空,则不会看到这些文件在此处的输出中.

In the case of a stash, if you've git add-ed files before running git stash, so that the i-vs-w diff is empty, you won't see those files in the output here.

最后,如果您使用git diff stash@{M} stash@{N}:这只是要求git diff比较不同的w ork-tree提交.含义是多少,取决于您要比较的内容,通常取决于储物袋的安装位置.

Last, if you git diff stash@{M} stash@{N}: this is just asking git diff to compare the different work-tree commits. How much meaning that has, depends on what you're comparing, which will generally depend upon where the stash-bags are attached.

1 确实是两个或三个,但是我将其绘制为两个.您使用git stash save(或简单的git stash,即git stash save)得到两次提交.如果添加-u-a选项以保存未跟踪的文件或所有文件,则会得到三次提交.这会影响隐藏存储,但不会影响git stash show命令的输出.

1Two or three, really, but I'm going to draw it as two. You get two commits with git stash save (or a plain git stash, which means git stash save). You get three commits if you add the -u or -a options to save untracked or all files. This affects stash restoration, but not the output from the git stash show command.

2 引用名称"只是一个名称,而不像分支或标记名称.参考名称有多种可能的形式.分支和标记只是具有特殊用途的名称. 远程分支"是这些引用的另一种形式,存储"也是引用.

2A "reference name" is just a name, rather like a branch or tag name. There are many possible forms of reference name. Branches and tags are just names with special purposes. "Remote branches" are another form of these references, and "stash" is a reference as well.

实际上,HEAD只是另一个参考,尽管它是一个非常特殊参考.我非常重要,如果您删除HEAD文件,git最终将决定您的存储库不再是存储库.

In fact, HEAD is just another reference, although it's a very special reference. I's so important that if you remove the HEAD file, git will decide that your repository is no longer a repository after all.

在某些特殊情况下,例如HEADORIG_HEADMERGE_HEAD等,所有引用均以字符串refs/开头.分支以refs/heads/开头,标签以refs/tags/开头,远程分支"以refs/remotes/开头.换句话说,引用具有一个名称空间",通常以refs/开头,然后在其下找到另一个单词以标识它们的住处.

With some special-case exceptions—HEAD, ORIG_HEAD, MERGE_HEAD, and so on—references all start with the string refs/. Branches start with refs/heads/, tags start with refs/tags/, and "remote branches" start with refs/remotes/. In other words, references have a "name space", generally starting with refs/ and then getting another word underneath that to identify where they live.

隐藏引用的拼写为refs/stash(并在此处停止,没有refs/stash/jimmy_kimmel或类似的东西).

The stash reference is spelled refs/stash (and stops there, there is no refs/stash/jimmy_kimmel or anything like that).

3 实际上,这确实使用引用日志.这意味着除其他以外,refs/stash以外的其他存储可以过期. (幸运的是,作为

3In fact, this really does use the reflog. This means, among other things, that stashes other than the "main" one, refs/stash, will can expire. (Fortunately, as musiphil notes, the default since git 1.6.0 is that these don't expire; you must configure expiration times for them to make this happen—which is probably not what you want anyway.)

4 巧妙的方式使用后缀^表示这一点,这在我的

4The clever way it does this, using the suffix ^ notation, is spelled out in my other answer.

5 如果要查看这些存储袋中的i ndex-commits,该怎么办?啊,好问题! :-)隐藏脚本没有一个好的答案.看到这些的简单方法是使用^2后缀来命名每个存储的第二个父级,即i提交.而且,如果您的存储中包含第三个提交(包含未跟踪的文件或所有文件),则该文件为第三个父文件:commit w看起来像是三父级合并,而stash^3则是第三个.但同样,w不是正常的合并,因此非常棘手.查看存储的所有部分的最佳简便方法可能是使用git stash branch将其变成自己的单独分支.

5What if you want to look at the index-commits in these stash bags? Ah, good question! :-) The stash script does not have a good answer. The easy way to see these is to use the ^2 suffix to name the second parent of each stash, which is the i commit. And, if you have a stash with a third commit containing untracked or all files, that's the third parent: commit w looks like a three-parent merge and stash^3 gets at the third one. But again, w is not a normal merge, so it's tricky. Probably the best easy way to look at all the parts of a stash is to turn it into its own separate branch, using git stash branch.

这篇关于`git stash show -p stash @ {N}`和`git show stash @ {N}`之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆