查找工作目录的Git修订版,缺少.Git目录



我有a)一个工作目录,没有.git目录和b)一个存储库。ab历史中期的一次修正。

如何找出ab中哪个版本匹配?

我想到了一个shellscript做diff从工作目录到所有的修订,并选择一个最小的差异(希望0)。

那就有点粗糙了(我不知道怎么做),有更简单的方法吗?

您可以编写一个脚本为每次提交运行diff gitdir workdir | wc -c。然后,您可以整理结果,并说具有最小差异的提交(由wc -c测量)是最接近裸工作目录的提交。

在Python中可能是这样的:

find_closestrongha1.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

你可以减少你必须用鹤嘴锄检查的修订次数。将您的工作目录与最新版本进行比较,并选择一些看起来尽可能少见的不同行。假设你的最新版本有一个包含foobar的行,但你的工作目录没有;运行git log -Sfoobar,输出所有添加或删除foobar的提交。现在,您可以将存储库移回该列表上的第一个(最新)版本,因为该版本之后的所有版本都将不同于您的工作目录。重复另一个不同的地方,直到找到正确的修订。

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

要使其工作,树显然需要完美匹配,因此您不能将任何未跟踪的文件(例如目标文件,编辑器备份等)放入提交。

编辑:我只是在一个存储库上尝试了这个(使用git cat-file commit HEAD在HEAD显示树对象,并搜索git log --pretty=raw的输出以获取该树哈希),并且它没有工作(我没有在历史中找到哈希)。当我做提交的时候,我确实得到了一堆关于CRLF转换的警告,所以这可能是问题所在,也就是说,你可能会得到不同的哈希值,这取决于你的git是如何配置为篡改文本文件的。我把这个答案标记为社区维基,以防有人知道如何可靠地做到这一点。

假设in-tree和b/.git忽略设置与创建提交时一样,并且在工作树中没有任何非忽略的未跟踪文件,您应该能够运行这样的操作。

策略是重新创建工作树的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

最新更新