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