从Git储藏中查找并提取文件

16

也许我经常使用git stash,但这是我想要删除项目中的实验时通常采用的方法。

问题1:

  • 如何在所有当前的stash中搜索文件名?

问题2:

  • 如何将该文件提取到单独的文件夹中?

  • 另一种选择:如何为该存储的文件启动可视化差异工具?


请参阅https://stackoverflow.com/questions/42555410/is-it-possible-to-search-through-git-stash-items,以获取对第一个问题的答案。 - undefined
4个回答

17

更加确切的是要认识到refs/stash是一个伪分支(ref)的引用日志(reflog):

git rev-list --walk-reflogs stash # (long option)
git rev-list -g stash # (short option)

因此您可以找到该文件:

for sha in $(git rev-list -g stash); 
do 
     git ls-tree -r $sha:; 
done |
   grep "$SOMEFILENAME" | 
   sort --unique
(The unique sort是为了删除不同stash中相同版本的重复项。)
例如:
$ for sha in $(git rev-list -g stash); do git ls-tree -r $sha:; done | grep numeric.js | sort -u
100644 blob f1c9a61910ae1bbd562615444a45688b93e9d808    LSPO.Web/DaVinci/JScript/numeric.js

你可以使用以下方式启动视觉差异比较:

kompare numeric.js <(git cat-file -p f1c9a61910ae1bbd562615444a45688b93e9d808)

当然,如果你已经有了一个直觉,知道哪个reflog包含了不同的文件,那么这将会更容易:

git diff stash@{3} -- numeric.js 

但是如何将存储的文件提取到单独的文件夹中呢?我认为这对于二进制存储文件非常重要,因为我们无法在存储中查看二进制差异。 - Terry Chen

8
@sehe提供的答案非常适合问题2。
我来到这个页面是为了寻找比我目前使用的更好的问题1的答案。我目前使用的是一个名为stashshowall.sh的Shell脚本,然后我会对输出进行grep操作。
我的答案不同之处在于,虽然其他答案告诉你要查找的文件是否被更改,但它们并不告诉你该文件位于哪个备份区(stash)中,以便在必要时应用该备份区。
我的答案纯粹使用“porcelain” Git 命令,但它对我非常有效。
#!/bin/sh
#  stashshowall.sh
for stash in `git stash list | sed 's/\(\w*\)\:.*/\1/'`
do
    echo
    echo "$stash"
    git stash show $stash
done

因此,回答问题1,我运行
> stashshowall.sh | grep "stash\|some-file"

这给了我

stash@{0}
stash@{1}
 .../some-dir/some-file     | 16 ++--
stash@{2}
stash@{3}
stash@{4}
 .../some-dir/some-file     | 2 ++--
stash@{5}

这样我就知道我需要应用或进一步查看stash{1}stash{4}


如果有人想要在Windows上从Git Bash运行:$ sh stashshowall.sh | grep "stash\|your_file" - Woland

7

tl;dr

grep stash for filename:

git reflog stash -- '*fileglob*'
git log -g stash -- '*fileglob*'

搜索stash以查找内容:
git stash list -G<regex>

搜索文件名对应的存储项

git帮助stash中得知:

你创建的最新存储项存储在refs/stash中;旧的存储项可以在此引用的reflog中找到,并且可以使用通常的reflog语法进行命名(例如stash@{0}...)

git帮助reflog中得知:

git reflog showgit log -g --abbrev-commit --pretty=oneline的别名。

git帮助log中得知:

-g
--walk-reflogs
不要遍历提交祖先链,而是从最近的一个向较旧的条目遍历reflog。

git log概述:

git log [<options>] [<revision range>] [[\--] <path>...]

Git修订规范中:

<refname>,例如master、heads/master、refs/heads/master
一个符号性的引用名称……
当有歧义时,通过以下规则找到第一个匹配的来消除<refname>的歧义:

  1. 如果存在$GIT_DIR/<refname>,那么就是指该引用(这通常只对HEADFETCH_HEADORIG_HEADMERGE_HEADCHERRY_PICK_HEAD有用);

  2. 否则,如果存在refs/<refname>,则指该引用;

现在我们把所有东西汇集在一起:

git reflog stash -- '*fileglob*'
git log -g stash -- '*fileglob*'

因此,我们的 stash 会被解析为 refs/stash,而 -g 将导致整个分支被遍历,`--'fileglob'` 将匹配该提交中的任何路径。

搜索 stash 内容

git help stash

... 该命令采用适用于 git log 命令的选项以控制显示内容和方式。请参见 git-log

来自git help log

-G<regex>
查找差异的补丁文本包含与 <regex> 匹配的已添加 / 已删除行的内容。

因此,简单的命令为:

git stash list -G<regex>

其他镐子命令也应该能够正常工作。


3
我使用这个命令在存储库中搜索文件: git stash list | cut -d ":" -f 1 | xargs -L1 git diff --stat | grep <filename> 您可以创建一个包含存储内容的新分支 (git checkout -b <new_branch> <stash>),然后将文件复制到其他地方并稍后合并回来。
您可以使用 git difftool 命令来获得您的差异的可视化效果。
编辑: 要获取存储的提交及其文件名,您可以使用以下 shell 脚本:
for i in $(git stash list | cut -d ":" -f 1 | xargs -L1 git show | grep commit |
  cut -d" " -f 2)
do
  if git show $i --oneline --stat | grep ht.h 
  then
    echo $i
  fi
done

它将在文件名下打印提交信息。

这只给了我文件名和删除/添加数量,有点没用。 - Petr Peller
如果你想知道提交记录,可以检查我的编辑。 - rohit89

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接