如何从git存储中提取单个文件(或更改文件)?

Dan*_*nny 714 git git-stash

我想知道是否可以从git stash中提取单个文件或diff文件,而不会弹出存储变更集.

任何人都可以提供一些关于此的建议/想法吗?

Jak*_*ski 1048

git stash手册页中,您可以阅读(在"讨论"部分,在"选项"描述之后):

存储表示为提交,其树记录工作目录的状态,其第一个父节点是创建存储时HEAD的提交.

因此,您可以将存储(例如stash@{0},第一个/最顶层的存储)视为合并提交,并使用:

$ git diff stash@{0}^1 stash@{0} -- <filename>
Run Code Online (Sandbox Code Playgroud)

说明:stash@{0}^1快捷方式表示给定存储的第一个父级,如上面的解释所述,提交时将更改隐藏起来.我们使用这种形式的"git diff"(有两个提交),因为stash@{0}/ refs/stash是一个合并提交,我们必须告诉git我们要对哪个父进行区分.更神秘:

$ git diff stash@{0}^! -- <filename>
Run Code Online (Sandbox Code Playgroud)

也应该工作(有关语法的解释,请参阅git rev-parse联机帮助页rev^!,在"指定范围"部分中).

同样,您可以使用git checkout从存储中检查单个文件:

$ git checkout stash@{0} -- <filename>
Run Code Online (Sandbox Code Playgroud)

或者将其保存在另一个文件名下:

$ git show stash@{0}:<full filename>  >  <newfile>
Run Code Online (Sandbox Code Playgroud)

要么

$ git show stash@{0}:./<relative filename> > <newfile>
Run Code Online (Sandbox Code Playgroud)

(请注意,<full filename>是文件的完整路径名,相对于项目的顶级目录(想想:相对于stash@{0})).


您可能需要保护stash@{0}shell扩展,即使用"stash@{0}"'stash@{0}'.

  • $ git checkout stash @ {0} - <filename>非常有用,谢谢 (75认同)
  • 请注意,`git checkout`方法从存储中复制_exact_文件 - 它不会将它与工作目录中的内容合并,如`git stash apply`.(因此,如果您创建了存储库,则从基础进行任何更改,它们将丢失). (40认同)
  • 这很酷......在我读到你的答案之前,我没有真正理解藏匿的工作原理(这导致我加入了git-checkout).我真的没有得到它,当你做一个存储时,git保存两个提交 - 一个用于索引的状态,一个用于工作副本的状态,这是索引和原始HEAD之间的合并.这解释了当我用存储器中的"gitk --all"可视化存储库时我看到的奇怪的树. (8认同)
  • 大多数情况下,我发现git checkout应用程序是完成我想要做的事情的最佳方式.然而,我很好奇,并仔细检查了`git checkout`的手册页.它不能将文件放入另一个位置.有一个参考:http://stackoverflow.com/questions/888414/git-checkout-older-revision-of-a-file-under-a-new-name/888623#888623 (4认同)
  • 请注意,为了使"git stash apply"合并自文件被存储以来在工作树中修改的文件中的更改,必须暂存工作树中的该文件.要使自动合并工作,不能在工作副本和要隐藏的待复制副本中修改相同的文件.最后,stash apply不会像`git stash pop`那样从stash中删除该项. (4认同)
  • git checkout“ stash @ {0}”如果得到“致命:无效引用:stash @ 0” (3认同)
  • @vrms:**如果**您已使用“--include-utracked”将未跟踪的文件保存到存储中,则包含_未跟踪文件_的树可作为“stash@{0}^2”使用,即_第二个父级stash_ (因此您可以使用 `git checkout 'stash@{0}^2' -- &lt;filename&gt;`)。您可以使用“git log --graph --oneline stash”看到这一点。 (3认同)
  • `git diff stash @ {0} ^ 1 stash @ {0} - <filename> | 补丁-p1` (2认同)
  • `git checkout stash@{0} -- &lt;path-to-folder&gt;` 也可以签出文件夹! (2认同)
  • 我不得不在Windows上用双引号括起来:"stash @ {0}:<full filename>" (2认同)
  • 至少如果存储列表中只有一项,只需键入“git checkout stash -- &lt;filename&gt;”即可正常工作,而无需在“stash”后添加“@{0}”。(它也可能适用于多个隐藏状态,但我没有尝试过,也不知道哪个状态是默认状态。) (2认同)
  • 在 PowerShell 中,需要将 `stash@{0}` 添加到单引号或反引号中。那是因为大括号在 PowerShell 中具有特殊含义。否则你会得到``错误:未知开关`e'``。 (2认同)

Tim*_*gan 41

如果您使用git stash apply而不是git stash pop,它会将存储应用于您的工作树但仍保留存储.

完成此操作后,您可以add/ commit您需要的文件,然后重置其余更改.

  • 这是最好的答案。您不必使用*不同*erent命令(呵呵)来执行 git stash apply 应该做的事情,并且您不必担心任何奇怪的副作用(git checkout 将确切的文件复制到存储中)或记住任何奇怪的语法。 (4认同)
  • 弹出一个特定的存储:`git stash pop stash @ {0}`(列出隐藏的更改:`git stash list`) (2认同)

Lub*_*rek 23

简短的回答

要查看整个文件: git show stash@{0}:<filename>

看到差异: git diff stash@{0}^1 stash@{0} -- <filename>

  • 这就是我一直在寻找的。然后你可以用 `difftool` 替换 `diff` 来使用你最喜欢的外部差异。 (3认同)

Wal*_*alf 23

有一种简单的方法可以从任何分支中获取更改,包括stashes:

$ git checkout --patch stash@{0} path/to/file
Run Code Online (Sandbox Code Playgroud)

如果要在许多部分进行修补,可以省略文件规范.或者省略补丁(但不是路径)以获取对单个文件的所有更改.如果您有多个0隐藏号码git stash list,请替换为隐藏号码.请注意,这就像diff,并提供应用分支之间的所有差异.要从单个提交/存储中获取更改,请查看git cherry-pick --no-commit.

  • @Danijel阅读`git help checkout`。“ --patch”进行交互式合并,它将应用您在外壳中批准的任何块(如果您选择“删除”补丁则保存任何内容)。就像我写的那样,仅路径会覆盖文件“所有更改”。 (2认同)

Ram*_*Ram 15

$ git checkout stash@{0} -- <filename>
Run Code Online (Sandbox Code Playgroud)

笔记:

  1. 确保在" - "和文件名参数后面加上空格

  2. 将零(0)替换为您的特定存储编号.要获取存储列表,请使用:

    git stash list
    
    Run Code Online (Sandbox Code Playgroud)

根据JakubNarębski的回答 - 更短的版本

  • 这有两个风险:(a) 它会默默地覆盖此文件中任何未暂存的本地更改;(b) 它从存储中复制 _exact_ 文件,而不将其与保存存储后在分支上所做的任何更改合并。这可能会令人困惑,因为 `git stash apply` / `pop` 没有这些陷阱。为了获得更预期的行为,请在此处的其他一些答案中使用基于“git diff”的方法之一。 (3认同)

Nat*_*hen 10

您可以使用" git show stash@{0}" 获取存储的差异(或者无论存储的数量是什么;请参阅"git存储列表").为单个文件提取diff的部分很容易.

  • 对于像我这样的人来说更简单:使用`git show stash`来显示最顶层的存储(通常是你唯一拥有的存储).类似地,您可以使用`git diff head stash`显示当前分支和存储之间的差异. (2认同)

cam*_*ous 10

使用以下内容将更改应用于存储中的文件到您的工作树。

git diff stash^! -- <filename> | git apply
Run Code Online (Sandbox Code Playgroud)

这通常比使用更好,git checkout因为您不会丢失自创建存储以来对文件所做的任何更改。


Phi*_*ati 5

要理解的最简单的概念,虽然可能不是最好的,但是您更改了三个文件,并且您希望存储一个文件.

如果你git stash要将它们全部藏起来,再将它们git stash apply带回来,然后再回到有git checkout f.c问题的文件上,以便有效地重置它.

当你想要释放该文件时,运行do git reset --hard然后git stash apply再次运行,利用git stash apply不清除存储堆栈中的差异的事实.