寻找缺失.git目录的工作目录的Git修订版本

8
我有两个目录:a是一个没有.git目录的工作目录,b是一个仓库,ab历史记录中的某个版本。如何找出ab中对应的版本号?
我考虑编写一个shell脚本,将工作目录与所有版本进行比较,并选择差异最小(希望为0)的版本。
这种方法有些原始(而且我不确定该怎么做),是否有更简单的方法?
4个回答

4
你可以编写一个脚本来运行每个提交的“diff gitdir workdir | wc -c”。然后你可以整合结果并说最小差异的提交(根据“wc -c”测量)是最接近裸工作目录的提交。
下面是 Python 代码示例:
find_closest_sha1.py:
#!/usr/bin/env python
import subprocess
import shlex
import sys
import os
import operator

gitdir,workdir=map(os.path.realpath,sys.argv[1:3])
os.chdir(gitdir)
proc=subprocess.Popen(shlex.split('git rev-list --all'),stdout=subprocess.PIPE)
shas,err=proc.communicate()
shas=shas.split()
head=shas[0]
data={}
for sha1 in shas:
    subprocess.Popen(shlex.split('git checkout {s}'.format(s=sha1)),
                          stderr=open('/dev/null')).wait()
    proc=subprocess.Popen(shlex.split('diff {g} {w}'.format(g=gitdir,w=workdir)),
                          stdout=subprocess.PIPE)
    out,err=proc.communicate()
    distance=len(out)
    data[sha1]=distance
answer=min(data.items(),key=operator.itemgetter(1))[0]
print('closest match: {s}'.format(s=answer))
subprocess.Popen(shlex.split('git checkout {h}'.format(h=head)),
                 stderr=open('/dev/null')).wait()

例子:

% rsync -a gitdir/ workdir/
% cd workdir
% git checkout HEAD~10
HEAD is now at b9fcebf... fix foo

% cd ..
% /bin/rm -rf workdir/.git
% find_closest_sha1.py gitdir workdir
closest match: b9fcebfb170785c19390ebb4a9076d11350ade79

这个Python脚本在我测试时完全失败了。它输出了一个完全错误的提交。 - Ian Kelling

1
你可以使用pickaxe来减少需要检查的修订次数。将你的工作目录与最新的修订进行差异比较,并选择一些看起来尽可能罕见的不同行。假设你的最新修订包含一个包含foobar的行,但是你的工作目录没有;运行git log -Sfoobar,它会输出添加或删除foobar的所有提交。现在,你可以将你的存储库移回到该列表上的第一个(最新)修订,因为该修订之后的所有修订都将与你的工作目录不同。重复以上步骤,直到找到正确的修订。

1

由于git使用内容可寻址的文件存储,因此应该可以在其中找到任意树,但我不知道细节。我猜你可以将分离的工作目录中的文件复制到存储库的工作目录中,然后提交所有内容,以某种方式找出由提交创建的树对象的哈希值,并搜索现有的提交以查找引用相同树的提交。

为了使其正常工作,树显然需要完全匹配,因此您不能将任何未跟踪的文件包含在提交中(例如对象文件、编辑器备份等)。

编辑:我刚刚在一个存储库上尝试了这个方法(使用git cat-file commit HEAD显示HEAD处的树对象,并在git log --pretty=raw的输出中搜索该树哈希),但它没有起作用(我没有在历史记录中找到哈希)。当我进行提交时,我得到了许多关于CRLF转换的警告,所以那可能是问题所在,即您可能会根据git配置的文本文件处理方式而获得相同树的不同哈希值。如果有人知道如何可靠地执行此操作,则我将标记此答案为社区wiki。


0

假设提交时的in-tree和b/.git ignore设置与创建时相同,并且工作树中没有非忽略的未跟踪文件,则您应该能够运行类似这样的命令。

策略是重新创建工作树的git ID,然后搜索包含此树的任何提交。

# work from detached working tree
cd a

# Use existing repository and a temporary index file
GIT_DIR=b/.git
GIT_INDEX_FILE=/tmp/tmp-index
export GIT_DIR GIT_INDEX_FILE

# find out the id of the current working tree
git add . &&
tree_id=$(git write-tree) &&
rm /tmp/tmp-index

# find a commit that matches the tree
for commit in $(git rev-list --all)
do
    if test "$tree_id" = "$(git rev-parse ${commit}^{tree})"; then
        git show "$commit"
        break
    fi
done

unset GIT_DIR
unset GIT_INDEX_FILE

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