【发布时间】:2010-11-09 11:13:18
【问题描述】:
是否可以从 git stash 中提取单个文件或文件的 diff 而不会弹出 stash 变更集?
【问题讨论】:
是否可以从 git stash 中提取单个文件或文件的 diff 而不会弹出 stash 变更集?
【问题讨论】:
您可以使用“git show stash@{0}”(或任何存储编号;请参阅“git stash list”)获取存储的差异。提取单个文件的差异部分很容易。
【讨论】:
git show stash 显示最顶层的存储(通常是你唯一拥有的)。同样,您可以使用git diff head stash 显示当前分支和存储之间的差异。
如果您使用git stash apply 而不是git stash pop,它会将存储应用到您的工作树,但仍会保留存储。
完成此操作后,您可以add/commit 所需的文件,然后重置剩余的更改。
【讨论】:
git stash pop stash@{0}(列出隐藏的更改:git stash list)
在git stash 联机帮助页上,您可以阅读(在“讨论”部分,就在“选项”描述之后):
一个 stash 表示为一个提交,其树记录了 工作目录,它的第一个父级是 HEAD 的提交,当 stash 已创建。
因此您可以将存储(例如stash@{0} 是第一个/最顶层的存储)视为合并提交,并使用:
$ git diff stash@{0}^1 stash@{0} -- <filename>
解释:stash@{0}^1 表示给定存储的第一个父级,如上面的解释中所述,是隐藏更改的提交。我们使用这种形式的“git diff”(有两个提交),因为stash@{0} / refs/stash 是一个合并提交,我们必须告诉 git 我们想要比较哪个父级。更神秘:
$ git diff stash@{0}^! -- <filename>
也应该可以工作(请参阅 git rev-parse 手册页以了解“指定范围”部分中的 rev^! 语法解释)。
同样,您可以使用git checkout 从存储中检查单个文件:
$ git checkout stash@{0} -- <filename>
或将其保存在另一个文件名下:
$ git show stash@{0}:<full filename> > <newfile>
或
$ git show stash@{0}:./<relative filename> > <newfile>
(注意这里 stash@{0})。
您可能需要保护stash@{0} 免受外壳扩展,即使用"stash@{0}" 或'stash@{0}'。
【讨论】:
git checkout 的手册页。它不能将文件放到另一个位置。对此有参考:stackoverflow.com/questions/888414/…
git checkout 方法会从存储中复制 exact 文件——它不会像 git stash apply 那样将其与工作目录中的内容合并。 (因此,如果您对创建存储的基础进行了任何更改,它们将会丢失)。
git stash apply 合并自文件被隐藏以来已在工作树中修改的文件中的更改,必须暂存工作树中的该文件。为了使自动合并起作用,不能在工作副本和隐藏的待合并副本中修改相同的文件。最后,stash apply 不会像 git stash pop 那样从 stash 中删除项目。
要理解的最简单的概念(虽然可能不是最好的)是您更改了三个文件并且想要存储一个文件。
如果您使用git stash 将它们全部隐藏起来,请git stash apply 将它们重新带回来,然后在相关文件上使用git checkout f.c 以有效地重置它。
如果您想取消存储该文件,请运行 git reset --hard,然后再次运行 git stash apply,利用 git stash apply 不会从存储堆栈中清除差异这一事实。
【讨论】:
查看整个文件:git show stash@{0}:<filename>
查看差异:git diff stash@{0}^1 stash@{0} -- <filename>
【讨论】:
diff 替换为difftool 以使用您最喜欢的外部差异。
编辑:参见cambunctious's answer,这基本上是我现在更喜欢的,因为它只使用存储中的更改,而不是将它们与您当前的状态进行比较。这使得操作具有附加性,自创建存储以来撤消已完成工作的机会要小得多。
要以交互方式进行,您首先要这样做
git diff stash^! -- path/to/relevant/file/in/stash.ext perhaps/another/file.ext > my.patch
...然后在文本编辑器中打开补丁文件,根据需要进行更改,然后执行
git apply < my.patch
cambunctious 的答案通过将一个命令直接传递给另一个命令来绕过交互性,如果您知道要从存储中进行所有更改,这很好。您可以将stash^! 编辑为具有所需累积更改的任何提交范围(但首先检查差异的输出)。
如果应用补丁/差异失败,您可以将最后一个命令更改为git apply --reject,这将进行所有可以更改的更改,并将.rej 文件留在无法解决的冲突中。然后可以使用wiggle 应用.rej 文件,如下所示:
wiggle --replace path/to/relevant/file/in/stash.ext{,.rej}
这将解决冲突,或为您提供从合并中获得的冲突标记。
如果您的发行版没有 wiggle,您可以直接构建它:
cd /usr/local/src/
git clone git://git.neil.brown.name/wiggle
cd wiggle/
git checkout v1.3
make install
以前的解决方案:有一种简单的方法可以从任何分支获取更改,包括存储:
$ git checkout --patch stash@{0} path/to/file
如果你想在很多部分打补丁,你可以省略文件规范。或者省略补丁(但不是路径)以获取对单个文件的所有更改。如果您有多个,请将 0 替换为 git stash list 中的存储编号。请注意,这类似于diff,并提供在分支之间应用所有差异。要从单个提交/存储中获取更改,请查看 git cherry-pick --no-commit。
【讨论】:
git help checkout。 --patch 进行交互式合并,它应用您在 shell 中批准的任何块(或者如果您选择 edit 补丁,则应用您保存的任何块)。单独的路径将覆盖文件,就像我写的那样,“所有更改”。
git config --global alias.applydiffat '!git checkout --patch "$1" -- $(git diff --name-only "$1"^ "$1")' -- 然后执行git applydiffat stash@{4} 仅使用在存储与其父级之间更改的文件。
$ git checkout stash@{0} -- <filename>
注意事项:
确保在“--”之后放置空格和文件名参数
将零 (0) 替换为您的特定存储编号。要获取存储列表,请使用:
git stash list
基于Jakub Narębski's answer -- 更短的版本
【讨论】:
git checkout stash^{/'Stash name here'} -- <filename>
如果隐藏的文件需要与当前版本合并,请使用之前使用 diff 的方法。否则,您可以使用git pop 来取消存储它们,git add fileWantToKeep 用于暂存您的文件,并使用git stash save --keep-index 来存储除舞台上的内容之外的所有内容。
请记住,这种方式与以前的不同之处在于它从 stash 中“弹出”文件。以前的答案保留它git checkout stash@{0} -- <filename>,以便根据您的需要进行。
【讨论】:
使用以下命令将更改应用到存储中的文件到您的工作树。
git diff stash^! -- <filename> | git apply
这通常比使用git checkout 更好,因为您不会丢失自创建存储以来对文件所做的任何更改。
【讨论】: