542

XXXというフォルダーに Git リポジトリがあり、YYYという 2 番目の Git リポジトリがあります。

XXXリポジトリをZZZという名前のサブディレクトリとしてYYYリポジトリにインポートし、すべてのXXXの変更履歴をYYYに追加したいと考えています。

以前のフォルダ構造:

├── XXX
│   ├── .git
│   └── (project files)
└── YYY
    ├── .git
    └── (project files)

後のフォルダ構造:

YYY
├── .git  <-- This now contains the change history from XXX
├──  ZZZ  <-- This was originally XXX
│    └── (project files)
└──  (project files)

これを行うことができますか、それともサブモジュールを使用する必要がありますか?

4

17 に答える 17

476

おそらく最も簡単な方法は、 XXXのものをYYYのブランチにプルしてから、マスターにマージすることです。

YYYで:

git remote add other /path/to/XXX
git fetch other
git checkout -b ZZZ other/master
mkdir ZZZ
git mv stuff ZZZ/stuff                      # repeat as necessary for each file/dir
git commit -m "Moved stuff to ZZZ"
git checkout master                
git merge ZZZ --allow-unrelated-histories   # should add ZZZ/ to master
git commit
git remote rm other
git branch -d ZZZ                           # to get rid of the extra branch before pushing
git push                                    # if you have a remote, that is

私は実際にいくつかのリポジトリでこれを試したところ、うまくいきました。Jörgの回答とは異なり、他のリポジトリを引き続き使用することはできませんが、とにかくそれを指定したとは思いません.

注: これは 2009 年に最初に作成されたため、git は以下の回答に記載されているサブツリーのマージを追加しました。もちろん、この方法はまだ機能しますが、今日はおそらくその方法を使用します。

于 2009-11-06T00:47:59.360 に答える
394

2 番目のリポジトリの正確なコミット履歴を保持し、将来的に上流の変更を簡単にマージする機能も保持したい場合は、次の方法が適しています。サブツリーの変更されていない履歴がリポジトリにインポートされ、マージされたリポジトリをサブディレクトリに移動するためのマージ コミットが 1 つ発生します。

git remote add XXX_remote <path-or-url-to-XXX-repo>
git fetch XXX_remote
git merge -s ours --no-commit --allow-unrelated-histories XXX_remote/master
git read-tree --prefix=ZZZ/ -u XXX_remote/master
git commit -m "Imported XXX as a subtree."

次のようにアップストリームの変更を追跡できます。

git pull -s subtree XXX_remote master

Git は、マージを実行する前にルートがどこにあるかを独自に把握するため、後続のマージでプレフィックスを指定する必要はありません。

欠点は、マージされた履歴では、ファイルの接頭辞が付けられていないことです (サブディレクトリではありません) 。その結果git log ZZZ/a、マージされた履歴以外のすべての変更 (ある場合) が表示されます。できるよ:

git log --follow -- a

ただし、マージされた履歴以外の変更は表示されません。

ZZZつまり、リポジトリ内の のファイルを変更しない場合は、接頭辞なしのパスXXXを指定する必要があります。--follow両方のリポジトリでそれらを変更すると、2 つのコマンドがあり、いずれもすべての変更を表示しません。

2.9 より前の Git バージョン--allow-unrelated-histories:オプションをに渡す必要はありませんgit merge

read-treeステップを使用してスキップする他の回答の方法は、merge -s ourscpでファイルをコピーして結果をコミットすることと実質的に違いはありません。

元のソースは、github の「サブツリー マージ」ヘルプ記事からのものです。そして別の便利なリンク.

于 2011-12-06T06:54:18.470 に答える
13

これを行う簡単な方法は、git format-patch を使用することです。

2 つの git リポジトリfoobarがあるとします。

fooには以下が含まれます。

  • foo.txt
  • 。ギット

バーには以下が含まれます:

  • bar.txt
  • 。ギット

そして、バーの履歴とこれらのファイルを含むfooで終了したいと考えています。

  • foo.txt
  • 。ギット
  • foob​​ar/bar.txt

それを行うには:

 1. create a temporary directory eg PATH_YOU_WANT/patch-bar
 2. go in bar directory
 3. git format-patch --root HEAD --no-stat -o PATH_YOU_WANT/patch-bar --src-prefix=a/foobar/ --dst-prefix=b/foobar/
 4. go in foo directory
 5. git am PATH_YOU_WANT/patch-bar/*

また、bar からのすべてのメッセージ コミットを書き換えたい場合は、Linux などで実行できます。

git filter-branch --msg-filter 'sed "1s/^/\[bar\] /"' COMMIT_SHA1_OF_THE_PARENT_OF_THE_FIRST_BAR_COMMIT..HEAD

これにより、各コミット メッセージの先頭に "[bar] " が追加されます。

于 2010-11-10T08:51:53.837 に答える
7

この記事に基づいて、サブツリーを使用するとうまくいき、該当する履歴のみが転送されました。誰かが手順を必要とする場合に備えて、ここに投稿します (プレースホルダーを適切な値に置き換えてください):

ソースリポジトリで、サブフォルダーを新しいブランチに分割します

git subtree split --prefix=<source-path-to-merge> -b subtree-split-result

宛先レポで、分割結果ブランチでマージします

git remote add merge-source-repo <path-to-your-source-repository>
git fetch merge-source-repo
git merge -s ours --no-commit merge-source-repo/subtree-split-result
git read-tree --prefix=<destination-path-to-merge-into> -u merge-source-repo/subtree-split-result

変更を確認してコミットする

git status
git commit

忘れないで

subtree-split-resultブランチを削除してクリーンアップする

git branch -D subtree-split-result

ソースリポジトリからデータを取得するために追加したリモートを削除します

git remote rm merge-source-repo

于 2015-04-29T15:57:08.207 に答える
1

私の場合、他のリポジトリ(XXX)から一部のファイルのみをインポートしたかったのです。サブツリーは私には複雑すぎて、他のソリューションは機能しませんでした。これは私がしたことです:

ALL_COMMITS=$(git log --reverse --pretty=format:%H -- ZZZ | tr '\n' ' ')

これにより、インポートしたいファイル(ZZZ)に影響を与えるすべてのコミットのスペース区切りのリストが逆の順序で表示されます(名前の変更もキャプチャするには、-followを追加する必要がある場合があります)。次に、ターゲットリポジトリ(YYY)に移動し、他のリポジトリ(XXX)をリモートとして追加し、そこからフェッチを実行して、最後に次のようにしました。

git cherry-pick $ALL_COMMITS

これにより、すべてのコミットがブランチに追加されます。これにより、すべてのファイルに履歴が含まれ、常にこのリポジトリにあるかのように、ファイルを使って好きなことを行うことができます。

于 2013-02-27T09:16:10.350 に答える
-2

私はそれを行う簡単な方法を知りません。あなたはこれを行うことができます:

  1. git filter-branch を使用して、XXX リポジトリに ZZZ スーパーディレクトリを追加します。
  2. 新しいブランチを YYY リポジトリにプッシュします
  3. プッシュされたブランチを YYY のトランクにマージします。

それが魅力的に聞こえる場合は、詳細を編集できます。

于 2009-11-05T21:06:03.310 に答える
-3

「git mv」と「git pull」を使用してこれを行うことができると思います。

私は公正な git noob です。メイン リポジトリには注意してください。ただし、これを一時ディレクトリで試してみたところ、うまくいくようです。

最初に - XXX の構造の名前を変更して、YYY 内にある場合の外観に一致させます。

cd XXX
mkdir tmp
git mv ZZZ tmp/ZZZ
git mv tmp ZZZ

XXX は次のようになります。

XXX
 |- ZZZ
     |- ZZZ

次に、「git pull」を使用して変更をフェッチします。

cd ../YYY
git pull ../XXX

YYY は次のようになります。

YYY
 |- ZZZ
     |- ZZZ
 |- (other folders that already were in YYY)
于 2009-11-05T21:05:09.223 に答える