2017-06-27 20 views
4

私は2つのgitリポジトリにAとBがあり、どちらもfile1.ccという名前のファイルが含まれています。 repo Aのfile1.ccの履歴をrepo Bのfile1.ccにマージ/コピーすることはできますか?Git:あるリポジトリから別のリポジトリにファイルの履歴をコピーする

問題は、既にファイルをrepo Aからrepo Bに移動し、すべてのファイルの履歴が失われていることです。しかし、今では開発者の一部が既にレポBの作業を開始し、変更をプッシュしています。だから今私は、レポAからレポBへのいくつかのファイルのマージ/コピー履歴を希望し、いくつかのファイルにのみ適用可能です。それは可能ですか?または失われたファイルの履歴は永遠に失われますか?

助けてください。前もって感謝します。

+1

なぜこれをやりたいのですか? –

答えて

5

できますが、それは簡単ではないかもしれません。しかし、最初にまず最初に:ファイルの履歴を移動することはありません。移動するコミットだけがあるので、ファイルのサブセットの履歴を表すコミットが必要な場合は、それらのコミットを作成することが最初の課題です。

最も簡単なのは、転送することですすべての履歴です。 (Repo BをRepo Bの浅いクローンとして作成した場合は、実際にはそれを浅くしてやることができますが、Repo Bの作成方法ではないと思います...)

Repo AからRepo Bに移行しているので、削除したい履歴があります。それは潜在的にそれ自身の全体的な話題ですが、実際には少数のファイルの履歴しか必要としないと仮定しましょう。

特別なケースでは、必要なすべてのファイルがサブディレクトリにあり、それらのファイルをリポジトリのルートディレクトリに移動したい場合は、filter-branchを使用できます--subdirectory-filter。より一般的に

我々はパスを想定した場合、変更しないでください、あなたがしたいファイルは、あなたが--index-filterfilter-branchを使用することができ、ツリー内の任意の場所にすることができました。

git filter-branch --index-filter 'git rm --cached --ignore-unmatch each file or *glob* you do NOT want' --prune-emtpy -- all 

レポに多くのコミットがあった場合、時間がかかることがあります。 rmへのファイルのリストが自明でない場合は、複数のgit rmコマンドをシェルスクリプトに入れ、それを上に示したようにインライン化する代わりに--index-filter引数として使用することができます。

まあ、一つの方法または他がうまくいけば、あなたがレポB.

cd repo-b 
git remote add repo-a path/to/repo-a 
git fetch repo-a 

にグラフトしたい歴史を持っている今、あなたはレポBを持っている:

... A -- B <--(repo-a/master) 
    \ 
    (repo-a/other-branches-maybe) 

B' -- C -- D (master)(origin/master) 

だから私Repo AでのコミットB - またはそのツリーの少なくとも一部が、Repo Bでルートコミットとしてインポートされたものです。

今、あなたは3つのオプションがあります:再親、リベースを、または私は最近の歴史の状態が古い履歴状態よりも重要である、と古い歴史は参考のために追加されていることを前提としていますので

を置き換え、一番安全なのは、CBです。だから、https://git-scm.com/docs/git-filter-branchあなたでし

# be sure you're on master 
echo "$commit-id $graft-id" >> .git/info/grafts 
git filter-branch $graft-id..HEAD 

$commit-idfilter-branchドキュメントから描画

(...あなたは代わりにAB'をリペアレントすることを選択することもできますが、私はあまり違いはありませんと仮定しています) B$graft-idのためのSHAはC

ためリベースは(履歴間の一貫性のあるレベルを想定して)少し簡単になるかもしれませんSHAですが、あなたはUを終了する可能性を紹介しています木をDに変更してください。あなたはリベースをしようとすることを決定したならば、それはB'がレポBルートがコミットのSHA IDで

git rebase --onto repo-A/master B' master 

だろう。 (あるいは

git rebase --interactive --onto repo-A/master --root master 

、次いでB'のエントリを削除します。)

これらのオプションのいずれかがコミットCDを書き換えます。 (再育児ではTREEが変更されないことが保証されますが、コミットは依然として置き換えられます)開発者はこれを上流リベースとして扱う必要があります(git rebase「上流リベースからの回復」を参照)。これを軽減するために、私は一般的に、devsが持っているすべてのものをチェックし、クローンを破棄した後、書き直しを行い、新しいリポジトリから再クローンを作成するコーディネートされたカットオーバーをお勧めします。

書き換えを避ける場合は、3番目のオプション:git replaceを使用できます。これにはいくつかの欠点があることが知られており、スプライスされた履歴を「見る」ためには、各クローンを正しくセットアップする必要があります。

だから、これをサポートするために、あなただけのBにタグを付ける(そしておそらくもB')したい:

git tag old-history repo-a/master 
git tag new-root B' 

B'が適切なSHA値のID、または同等の式です)。誰かがレポのクローンとき

は、彼らが唯一の新しい歴史を見ることができますが、彼らは

git replace new-root old-history 

と歴史の中で休憩を超えるこの意志紙を言うことができます。

親のリベース、リベース、または置き換えが完了したら、repo-aリモートを削除できます。

+0

これは確かに私が達成しようとしているものです。どうもありがとう。 –

+0

私はまた、gitpythonを使ってスクリプトを書こうとしましたが、時間がかかりました:(。 –

+0

これは私のためにはうまくいったが、最初に私を捨てたのは、 '' '--index-filter – rbhitchcock

関連する問題