找到缺少.git目录的工作目录的Git修订版

时间:2011-10-15 17:19:13

标签: git find revision working-directory

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

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

我想到了一个从工作目录中执行diff的shellcript到所有修订版本,并选择一个具有最小(希望是0)差异的版本。

那会有点原始(我不知道该怎么做),有更简单的方法吗?

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

为了实现这一点,树显然需要完美匹配,因此您不能将任何非跟踪文件放入提交中(例如目标文件,编辑器备份等)。

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

答案 3 :(得分:0)

假设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