如何在Git中检查签出文件的提交id?

如何在Git中检查签出文件的提交id?,git,version,commit,Git,Version,Commit,假设我的存储库中有三次提交文件a.txt: >git log -- a.txt commit 63cfed7cebe84009aa4fba6e4a62ea5b0bec7660 commit 874028c921f22e0c3e44d0faf13eef2b7638d3ff commit 0a89b0751afdb111ba775922e85bbac6302f727c 然后我发出命令 >git checkout 874028c921f22e0c3e44d0faf13eef2b7638d

假设我的存储库中有三次提交文件a.txt:

>git log -- a.txt
commit 63cfed7cebe84009aa4fba6e4a62ea5b0bec7660
commit 874028c921f22e0c3e44d0faf13eef2b7638d3ff
commit 0a89b0751afdb111ba775922e85bbac6302f727c
然后我发出命令

>git checkout 874028c921f22e0c3e44d0faf13eef2b7638d3ff  a.txt 
将文件a.txt签出回v1

假设稍后我忘记了a.txt的工作版本是从哪个提交中签出的。是否有我可以用来确定该信息的命令

我尝试了以下方法:

>git log --a.txt
它显示此文件的所有提交日志

>git status 
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
      modified:   a.txt
>git状态
论分行行长
要提交的更改:
(使用“git重置磁头…”取消分级)
修改:a.txt
但这些都不是我想要的。我需要查看a.txt的当前版本。那么,我可以使用什么命令来确定当前a.txt的commit_id

假设稍后我忘记了a.txt的工作版本是从哪个提交中签出的。是否有我可以用来确定该信息的命令

否(但请参阅以获得一种相对快速的方法来搜索具有与索引版本匹配的同名文件的某些提交;这可能已经足够接近了)。这有几个原因:

  • Git会跟踪您当前的提交。那只是头。但它不会跟踪每个工作树文件的一次提交
  • 就这一点而言,工作树文件一开始就很难跟踪。程序、编辑或人员都在不断地改变它们
  • 同时,对于从某个提交中提取的每个文件,Git在索引中都有该文件的“原始副本”。简而言之,您的索引是构建下一个提交的的地方。如果您已经修改了工作树中的一个文件,并且希望在下次提交时使用新版本,那么您可以
    git添加该文件以将新版本复制到索引中。否则,索引仍然保留旧版本
索引中的文件版本确实具有哈希ID,类似于提交哈希ID。(事实上,Git中的commit和file或blob对象的哈希ID的计算方法相同。Git的另外两种内部对象类型也是如此。)但是,尽管提交的哈希ID对于该提交是唯一的,但文件版本的哈希ID对于某个特定提交并不是唯一的

例如,考虑以下顺序:

mkdir tmp && cd tmp && git init
(现在我们有了一个新的空临时目录来存放新的存储库)

这个新的Git存储库有一个提交,其中有两个文件,
README
file.txt
。索引中还有两个文件,
README
file.txt
。现在我们修改
file.txt
并提交新的文件:

echo more data >> file.txt
git add file.txt
git commit -m 'added more'
您的存储库现在有两个提交。第二次提交与第一次提交具有相同的
自述文件。文件在其“blob”散列下存储一次,两个不同的提交(和索引)都使用相同的散列ID来表示“该数据的版本”

事实上,如果我们现在重命名
README
文件:

git mv README README.md
git commit -m 'rename README'
我们现在有三个提交,并且所有三个提交(以及索引)都共享blob对象的一个版本。最新的提交调用blob对象
README.md
,而之前的两个提交调用它
README
,但这三个对象都具有相同的哈希ID

Git无法存储从中提取某个blob哈希的索引版本的提交的哈希ID有一个次要的技术原因:当您这样做时:

git checkout <hash> -- <path>
全部显示,您可以使用
git rev parse
查找单个。然后,如果愿意,您可以搜索部分或全部提交,找到它们的树对象,读取这些树,并搜索它们以查找该散列。如果在某些树中找到散列,则可以说文件的索引版本出现在这些路径名下的提交中

因此,给定上述存储库索引中的
README.md
散列,我们可以搜索所有三个提交,读取它们的树,并发现索引中当前作为
README.md
的内容与两个提交中存储为
README
的内容以及当前(HEAD)提交中存储为
README.md
的内容相匹配

假设稍后我忘记了a.txt的工作版本是从哪个提交中签出的。是否有我可以用来确定该信息的命令

否(但请参阅以获得一种相对快速的方法来搜索具有与索引版本匹配的同名文件的某些提交;这可能已经足够接近了)。这有几个原因:

  • Git会跟踪您当前的提交。那只是头
。但它不会跟踪每个工作树文件的一次提交
  • 就这一点而言,工作树文件一开始就很难跟踪。程序、编辑或人员都在不断地改变它们
  • 同时,对于从某个提交中提取的每个文件,Git在索引中都有该文件的“原始副本”。简而言之,您的索引是构建下一个提交的的地方。如果您已经修改了工作树中的一个文件,并且希望在下次提交时使用新版本,那么您可以
    git添加该文件以将新版本复制到索引中。否则,索引仍然保留旧版本
  • 索引中的文件版本确实具有哈希ID,类似于提交哈希ID。(事实上,Git中的commit和file或blob对象的哈希ID的计算方法相同。Git的另外两种内部对象类型也是如此。)但是,尽管提交的哈希ID对于该提交是唯一的,但文件版本的哈希ID对于某个特定提交并不是唯一的

    例如,考虑以下顺序:

    mkdir tmp && cd tmp && git init
    
    (现在我们有了一个新的空临时目录来存放新的存储库)

    这个新的Git存储库有一个提交,其中有两个文件,
    README
    file.txt
    。索引中还有两个文件,
    README
    file.txt
    。现在我们修改
    file.txt
    和comm
    git ls-files --stage
    
    git hash-object a.txt
    
    for rev in $(git rev-list --all); do git ls-tree -r $rev | grep -q <SHA1> && echo $rev ; done
    
    find=$(git rev-parse :a.txt)   # as staged i.e. last checked out or added
    for commit in $(git rev-list @ -- a.txt); do 
            [[ $(git rev-parse $commit:a.txt) = $find ]] && { echo $commit; break; }
    done