【问题标题】:Find when a file was deleted in Git在 Git 中查找文件何时被删除
【发布时间】:2011-10-13 22:35:38
【问题描述】:

我有一个包含 n 次提交的 Git 存储库。

我有一个我需要的文件,它曾经在存储库中,我突然寻找并想“哦!那个文件去哪儿了?”

是否有(一系列)Git 命令会告诉我“文件真的需要.txt 在提交 n-13 时被删除”?

换句话说,如果不查看每个单独的提交,并且知道我的 Git 存储库包含每个文件的所有更改,我是否可以快速找到包含该文件的最后一个提交,以便将其取回?

【问题讨论】:

标签: git


【解决方案1】:

git log --full-history -- [file path] 显示文件的变化,即使文件被删除也能正常工作。

例子:

git log --full-history  -- [file path]

如果您只想查看删除文件的最后一次提交,请在上面的命令之外使用-1。示例:

git log --full-history -1 -- [file path]

另见我的文章:Which commit deleted a file。

【讨论】:

  • 是否可以搜索模式?我忘记了文件的全名=(也许可以获得所有删除的日志?
  • 请注意,如果您使用的是 PowerShell,则必须对连字符进行转义:git log '--' [file path]。希望这可以让其他人咬牙切齿。
  • 我能够使用 git log -- */<<filename>>.<<file extension>> 进行搜索,但不知道整个文件路径。
  • @MERose 方括号作为真实文件路径的占位符。
【解决方案2】:

简答:

git log --full-history -- your_file

将向您显示您的存储库历史中的所有次提交,包括涉及your_file 的合并提交。最后一个(顶部)是删除文件的那个。

一些解释:

这里的--full-history 标志很重要。没有它,当你向它询问文件的日志时,Git 会执行“历史简化”。文档详细说明了它的工作原理,我缺乏尝试从源代码中找出答案所需的勇气和勇气,但the git-log docs 有很多话要说:

默认模式

将历史简化为解释树最终状态的最简单历史。最简单,因为如果最终结果相同(即合并具有相同内容的分支),它会修剪一些侧分支

这显然与我们想要其历史记录的文件何时被删除有关,因为解释已删除文件的最终状态的最简单历史记录是无历史记录。没有--full-history 的git log 是否会简单地声称该文件从未创建过?不幸的是,是的。这是一个演示:

mark@lunchbox:~/example$ git init
Initialised empty Git repository in /home/mark/example/.git/
mark@lunchbox:~/example$ touch foo && git add foo && git commit -m "Added foo"
[master (root-commit) ddff7a7] Added foo
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 foo
mark@lunchbox:~/example$ git checkout -b newbranch
Switched to a new branch 'newbranch'
mark@lunchbox:~/example$ touch bar && git add bar && git commit -m "Added bar"
[newbranch 7f9299a] Added bar
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bar
mark@lunchbox:~/example$ git checkout master
Switched to branch 'master'
mark@lunchbox:~/example$ git rm foo && git commit -m "Deleted foo"
rm 'foo'
[master 7740344] Deleted foo
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 foo
mark@lunchbox:~/example$ git checkout newbranch
Switched to branch 'newbranch'
mark@lunchbox:~/example$ git rm bar && git commit -m "Deleted bar"
rm 'bar'
[newbranch 873ed35] Deleted bar
 1 file changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 bar
mark@lunchbox:~/example$ git checkout master
Switched to branch 'master'
mark@lunchbox:~/example$ git merge newbranch
Already up-to-date!
Merge made by the 'recursive' strategy.
mark@lunchbox:~/example$ git log -- foo
commit 77403443a13a93073289f95a782307b1ebc21162
Author: Mark Amery 
Date:   Tue Jan 12 22:50:50 2016 +0000

    Deleted foo

commit ddff7a78068aefb7a4d19c82e718099cf57be694
Author: Mark Amery 
Date:   Tue Jan 12 22:50:19 2016 +0000

    Added foo
mark@lunchbox:~/example$ git log -- bar
mark@lunchbox:~/example$ git log --full-history -- foo
commit 2463e56a21e8ee529a59b63f2c6fcc9914a2b37c
Merge: 7740344 873ed35
Author: Mark Amery 
Date:   Tue Jan 12 22:51:36 2016 +0000

    Merge branch 'newbranch'

commit 77403443a13a93073289f95a782307b1ebc21162
Author: Mark Amery 
Date:   Tue Jan 12 22:50:50 2016 +0000

    Deleted foo

commit ddff7a78068aefb7a4d19c82e718099cf57be694
Author: Mark Amery 
Date:   Tue Jan 12 22:50:19 2016 +0000

    Added foo
mark@lunchbox:~/example$ git log --full-history -- bar
commit 873ed352c5e0f296b26d1582b3b0b2d99e40d37c
Author: Mark Amery 
Date:   Tue Jan 12 22:51:29 2016 +0000

    Deleted bar

commit 7f9299a80cc9114bf9f415e1e9a849f5d02f94ec
Author: Mark Amery 
Date:   Tue Jan 12 22:50:38 2016 +0000

    Added bar

请注意上面终端转储中的git log -- bar 是如何导致字面上没有输出的; Git 正在将历史“简化”成bar 从未存在过的小说。另一方面,git log --full-history -- bar 为我们提供了创建 bar 的提交和删除它的提交。

要明确:这个问题不仅仅是理论上的。我只查看了文档并发现了--full-history 标志,因为git log -- some_file 在我试图追踪已删除文件的真实存储库中失败了。当您试图了解 当前存在的 文件如何进入其当前状态时,历史简化有时可能会有所帮助,但在尝试追踪文件时删除隐藏你关心的提交更有可能把你搞砸。在此用例中始终使用 --full-history 标志。

【讨论】:

  • 请注意,这仅搜索与当前分支相关的历史记录(而不是“整个回购历史记录”)...即如果文件尚未在当前分支中删除但已在另一个分支中,则不会t 找到删除提交。您必须在文件已被删除的任何分支上。想起来可能很明显,但一开始我就被吸引住了。
  • 这个答案有效。但从git log 输出本身来看,最后一次提交已删除文件一点也不明显。我还尝试了git log --name-status --full-history -- file_name 和git log -p --stat --full-history -- file_name,但都没有明确表明该文件已在最新提交中被删除。这似乎是一个错误。
  • @Martin_ATS mkdir somedir && cd somedir && git init && touch foo && git add foo && git commit -m "Added foo" && git checkout -b newbranch && touch bar && git add bar && git commit -m "Added bar" && git checkout master && git rm foo && git commit -m "Deleted foo" && git checkout newbranch && git rm bar && git commit -m "Deleted bar" && git checkout master && git merge newbranch && git log --name-status --full-history -- bar 在 Git 2.12.2 的日志输出中包括 D bar 和 A bar。您没有在输出中看到这些行吗?你有什么版本?
  • git version 2.15.1 是的,您的命令序列确实报告了D bar 和A bar。也许我的问题与我的文件历史有关。我正在跟踪一个.htaccess 文件的历史记录,该文件被 gitignore'ed 和删除。我终于想通了并将文件添加回来。当我在git log 命令中包含--name-status 时,我看到两个A .htaccess 条目(因为我在最新提交中添加了它)但没有D .htaccess。所以在某些情况下,即使文件已从存储库中删除,git log 也不会显示明确的D file_name 条目。
  • @Martin_ATS 好奇。我想知道.htaccess 是否可能被添加到提交 X 中,但随后没有包含在将 X 带到 master 的合并提交中?这是我能想到的唯一一件事,我可能会争辩说应该看起来像一个已添加且从未删除但仍不存在的文件。尝试找出一个 MCVE 会很有趣,然后找出它是否是 Git 错误,如果不是,是否可以调整我的答案来处理您的情况。
【解决方案3】:

Git 日志,但您需要在路径前加上 --

例如:

dan-mac:test dani$ git log file1.txt
fatal: ambiguous argument 'file1.txt': unknown revision or path not in the working tree.

dan-mac:test dani$ git log -- file1.txt
 commit 0f7c4e1c36e0b39225d10b26f3dea40ad128b976
 Author: Daniel Palacio <danpal@gmail.com>
 Date:   Tue Jul 26 23:32:20 2011 -0500

 foo

【讨论】:

    【解决方案4】:

    你可以找到最后一次提交的删除文件如下:

    git rev-list -n 1 HEAD -- [file_path]
    

    更多信息可here

    【讨论】:

    • 首选的解决方案对我不起作用,但这个解决方案对我有用。
    • 这个解决方案对我有用。接受的解决方案没有。
    • 对我来说也一样,这个解决方案效果很好,而接受的答案却没有。非常感谢,很棒的提示!
    • 请注意,模式匹配在这里也有效。例如:git rev-list -n 1 HEAD -- '*myfile.txt'
    • 这个也对我有用。赞成的答案包括一堆由于某种原因实际上没有触及文件的提交。无论如何,谢谢@Akif
    【解决方案5】:

    我刚刚在(is there a way in git to list all deleted files in the repository?) 添加了一个解决方案,用于使用正则表达式查找已删除文件的提交:

    git log --diff-filter=D --summary | sed -n '/^commit/h;/\/some_dir\//{G;s/\ncommit \(.*\)/ \1/gp}'
    

    这将返回在名为some_dir(级联)的目录中删除的所有内容。 \/some_dir\/ 所在的任何 sed 正则表达式都可以。

    OSX(感谢@triplee 和@keif)

    git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
    

    【讨论】:

    • 不错。 OS X 中 bash 下的一些不匹配:sed: 1: "/^commit/h;/\/some_dir\ ...": bad flag in substitute command: '}'
    • @BrentFoust 可惜我无法测试...尝试在末尾添加一个空格(在大括号之后但在单引号之前),在线手册页不清楚...
    • 不错的建议。但是在单引号之前添加一个空格并没有帮助。右大括号前也没有空格。
    • BSD/OSX sed 显然并不总是用分号作为命令分隔符。尝试将它们更改为换行符,或切换到sed -n -e '/^commit/h' -e '\:/some_dir/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e }
    • 我测试了它,git log --diff-filter=D --summary | sed -n -e '/^commit/h' -e '\:/:{' -e G -e 's/\ncommit \(.*\)/ \1/gp' -e } 在 OSX 上为我工作。
    【解决方案6】:

    试试:

    git log --stat | grep file
    

    【讨论】:

    • Grep 本身不会很有用,因为它只会给出被删除的文件名。如果你想得到 git 哈希,那么你可以使用grep -C 10 在文件名周围获取 +-10 行(应该包括 git 哈希)。
    • 我的文件名错误,这有助于我找到正确的文件。
    【解决方案7】:

    这个命令对我不起作用:

    git log --full-history -1 -- [file path]
    

    这是有效的命令:

    git log --follow -- [file path]
    

    【讨论】:

    • 不知道为什么这条评论没有得到更多的支持——第二条命令也对我有用。
    【解决方案8】:

    这对我有用:

    git 日志 -- **/Myfile.cs

    如果包含--full-history开关,会显示很多与文件无关的改动。不知道为什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-14
      • 1970-01-01
      • 2021-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-01
      相关资源
      最近更新 更多