2011-10-15 15 views
8

私はaを持っています).gitディレクトリのない作業ディレクトリとb)リポジトリを持っています。 aは、bの歴史の中間にある改訂版です。作業ディレクトリのGitリビジョンを見つける.gitディレクトリがありません

どのようなリビジョンaが一致するかは、bで確認できますか?

私は、作業ディレクトリからすべてのリビジョンまでdiffを実行しているシェルスクリプトを考え、最小の(うまくいけば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() 

例:ツリーインとb/.gitと仮定すると

% 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 
+0

私がテストしたとき、pythonスクリプトは完全に失敗しました。それは完全に間違っていたコミットを出力します。 –

1

pickaxeでチェックするリビジョンの数を減らすことができます。作業ディレクトリと最新のリビジョンとを比較し、できるだけ稀に見えるいくつかの異なる行を選択します。最新のリビジョンにfoobarという行がありますが、作業ディレクトリには含まれていないとします。 を実行すると、すべてのコミットが出力され、foobarが追加または削除されます。リポジトリをそのリストの最初の(最新の)リビジョンに戻すことができるようになりました。リビジョンの後のすべてのリビジョンが作業ディレクトリと異なるためです。正しいリビジョンが見つかるまで、別の違いを繰り返してください。

1

gitはコンテンツアドレス可能なファイルストアを使用しているので、どこかで任意のツリーを見つけることができるはずですが、詳細はわかりません。私は、デタッチされた作業ディレクトリからリポジトリの作業ディレクトリにファイルをコピーしてからすべてをコミットし、コミットによって作成されたツリーオブジェクトのハッシュを見つけて、同じツリーを参照する既存のコミットを検索することができます。

これを行うには、ツリーが完全に一致する必要があります。したがって、追跡されていないファイル(オブジェクトファイルやエディタのバックアップなど)をコミットに含めないでください。

編集:これは、1つのリポジトリでgit cat-file commit HEADを使用してHEADのツリーオブジェクトを表示し、そのツリーハッシュに対してgit log --pretty=rawの出力を検索しましたが、動作しませんでした(ハッシュが見つかりませんでした歴史の中で)。コミットしたときにCRLF変換に関する警告が表示されたので、問題が発生している可能性があります。つまり、gitがテキストファイルをmangleする方法に応じて、同じツリーに対して異なるハッシュを取得するでしょう。私は誰かがこれを確実に行う方法を知っている場合に備えて、このコミュニティウィキをマークしています。

0

無視設定は、コミットが作成されたときの設定と同じです。作業ツリーに非トラッキングされていないファイルはありません。このようなファイルを実行できるはずです。

作業ツリーの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 
関連する問題