私はa
) ディレクトリのない作業ディレクトリ.git
とb
) リポジトリを持っています。a
の歴史の途中でのいくつかの改訂ですb
。
でどのリビジョンがa
一致するかを調べるにはどうすればよいb
ですか?
diff
作業ディレクトリからすべてのリビジョンにシェルスクリプトを実行し、違いが最も少ない(できれば0)ものを選択することを考えました。
それは少し生です (そして、私はそれを行う方法がわかりません)、もっと簡単な方法はありますか?
私はa
) ディレクトリのない作業ディレクトリ.git
とb
) リポジトリを持っています。a
の歴史の途中でのいくつかの改訂ですb
。
でどのリビジョンがa
一致するかを調べるにはどうすればよいb
ですか?
diff
作業ディレクトリからすべてのリビジョンにシェルスクリプトを実行し、違いが最も少ない(できれば0)ものを選択することを考えました。
それは少し生です (そして、私はそれを行う方法がわかりません)、もっと簡単な方法はありますか?
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
つるはしでチェックしなければならないリビジョンの数を減らすことができます。作業ディレクトリを最新のリビジョンと比較して、できるだけ珍しいように見えるいくつかの異なる行を選択します。最新のリビジョンには行が含まれているfoobar
が、作業ディレクトリには含まれていないとします。rungit log -Sfoobar
を追加または削除するすべてのコミットを出力しますfoobar
。リポジトリをそのリストの最初の (最新の) リビジョンに戻すことができます。それ以降のリビジョンはすべて作業ディレクトリとは異なるためです。正しいリビジョンが見つかるまで、別の違いで繰り返します。
git はコンテンツ アドレス指定可能なファイル ストアを使用するため、どこかに任意のツリーを見つけることができるはずですが、詳細はわかりません。デタッチされた作業ディレクトリからリポジトリの作業ディレクトリにファイルをコピーしてから、すべてをコミットし、コミットによって作成されたツリーオブジェクトのハッシュを見つけて、同じツリーを参照する既存のコミットを検索できると思います.
これが機能するには、明らかにツリーが完全に一致する必要があるため、追跡されていないファイル (オブジェクト ファイル、エディターのバックアップなど) をコミットに含めてはなりません。
編集:これを1つのリポジトリで試しました(git cat-file commit HEAD
HEADでツリーオブジェクトを表示し、git log --pretty=raw
そのツリーハッシュの出力を検索しました)が機能しませんでした(履歴にハッシュが見つかりませんでした)。コミットを行ったときに CRLF 変換に関する警告がたくさん表示されたので、それが問題だった可能性があります。つまり、テキスト ファイルをマングルするように git がどのように構成されているかによって、同じツリーに対して異なるハッシュが得られる可能性があります。誰かがこれを確実に行う方法を知っている場合に備えて、この回答コミュニティ wiki にマークを付けます。
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