【问题标题】:Find to which git commit a file belongs?查找文件属于哪个 git commit?
【发布时间】:2016-12-01 22:57:08
【问题描述】:

给定一个随机文件,是否有一种规范的方法可以从命令行确定该文件是否属于特定的提交?

这类似于堆栈溢出问题find-out-which-git-commit-a-file-was-taken-from,只是我希望能够在脚本中使用它并且不创建临时分支。

【问题讨论】:

  • @Bryce 我问的原因是(使用 git)我总是怀疑有一些命令,如“git ls-tree --do-something-magical 正是我想要的。就像当我用 Python 编写了一个方便的 git sha-1 计算器几分钟后发现了“git hash-object”!
  • 一个例子是当有人将配置文件(从硬件检索)发送到支持层,直到它被移交以进行验尸或诊断。它来自什么提交或发布?在过去的日子里,我们为此使用了 RCS(最终是 CVS)关键字扩展。我很确定我们可以使用 commit 和 checkout hooks 来添加虚假的关键字扩展,但它是如此的混乱,以至于我什至有点不好意思提及它。
  • 该链接表明,从您的第二条评论中可以清楚地看出,您正在谈论一个不属于您的工作树的文件——但问题本身并没有这么说。听起来您只是在要求git log -1 -- $filename(可能对“属于”的含义有些混淆)。你能改写一下吗?

标签: git


【解决方案1】:

以下是我为此目的使用的脚本的摘录。我使用我有限的 git 知识和在网络上找到的其他脚本片段一起破解了它。它工作得很好,但我经常发现在 git 中做事的方法比我通过反复试验学到的更简单。

FILE=$1

# git hash for file
HASH=`git hash-object $FILE`

# git revisions for file
REVS=`git log --pretty=%H -- $FILE`

# check each revision for checksum match
for rev in $REVS; do
    POSSIBLE=`git ls-tree $rev $FILE | awk '{print $3}'`
    if [[ $HASH == $POSSIBLE ]]; then
        echo $rev
    fi
done

【讨论】:

  • 除了将git log --pretty=... 更改为git rev-list --all -- $FILE 之外,我不会更改您的答案。
【解决方案2】:

Your approach 可能会在文件的本地版本和存储库版本之间存在微小差异(例如,行尾样式,或由于干净/涂抹过滤器造成的差异)时无法工作。

以下脚本通过git diff 工作,而不是依赖于哈希。它接受文件名后的差异选项。

用法示例:

# list all commits that introduce the file README.md in its local state
list_introducing_commits README.md

# list all commits that introduce the file README.md in its local state
# ignoring any difference in whitespace
list_introducing_commits README.md -w

list_introducing_commits(找不到更好的名称):

#!/bin/bash

if [ $# -eq 0 ]
then
    echo "Usage: $(basename $0) path/to/file [<diff-options>]"
    exit 1
fi

file="$1"
shift 1

for rev in $(git log --pretty=%H -- "$file")
do
    if git diff --exit-code $@ $rev -- $file &> /dev/null
    then
        echo $rev
    fi
done

【讨论】:

    【解决方案3】:

    基于DavidNanswer,如果文件在当前工作树中,并且工作树与HEAD同步,这将为您提供与文件当前内容对应的提交:

    git log --pretty="%H" -1  -- path/to/file
    

    但您可能希望通过“git diff --exit-code /path/to/file”提前测试这些假设并查看$?

    【讨论】:

      【解决方案4】:

      你的意思是,文件在提交中被修改了吗?如果是这样,git log --oneline -- filePathName 之类的东西应该列出来自 HEAD 的提交。

      在二读时,我认为您只是要求提交包含该文件的提交,无论它是否已更改。如果是这样,那么您的 ls-tree 不需要 -r 标志来递归到其子树(子目录)吗?如果您仅在 sha 上匹配,它将找到任何名称下的文件的任何副本。

      【讨论】:

      • 这似乎返回了所有涉及该文件名的提交 - 但不是包含文件的特定提交,该文件处于当前的确切状态。
      • 啊,好的,所以您正在寻找该文件的完全匹配。那么,您不应该递归(上图)并寻找每个 blob 的 sha 与您尝试匹配的文件的 sha 的匹配项吗?
      猜你喜欢
      • 2015-10-04
      • 2016-08-08
      • 2012-02-14
      • 1970-01-01
      • 2020-10-30
      • 2019-06-18
      • 2016-09-09
      • 2016-03-20
      • 2020-09-15
      相关资源
      最近更新 更多