261

2 つの Git リポジトリを新しい 3 つ目のリポジトリにマージする必要があります。サブツリーのマージを使用してこれを行う方法についての多くの説明を見つけました (たとえば、2 つの Git リポジトリをどのようにマージしますか?に関するJakub Narębski の回答) 。古いリポジトリからのファイルは、新しく追加されたファイルとして記録されます。実行すると、古いリポジトリからのコミット履歴を確認できますが、実行すると、そのファイルのコミットが 1 つだけ表示されます - サブツリー マージ。上記の回答に対するコメントから判断すると、この問題を目にしたのは私だけではありませんが、公開された解決策は見つかりませんでした。git loggit log <file>

リポジトリをマージして個々のファイル履歴をそのまま残す方法はありますか?

4

9 に答える 9

306

外部依存関係を管理するのではなく、単純に 2 つのリポジトリをくっつけて、最初からそうだったように見せようとしている場合、答えははるかに簡単であることがわかります。古いリポジトリにリモートを追加し、それらを新しいマスターにマージし、ファイルとフォルダーをサブディレクトリに移動し、移動をコミットし、追加のすべてのリポジトリに対して繰り返すだけです。サブモジュール、サブツリーのマージ、および派手なリベースは、わずかに異なる問題を解決することを目的としており、私がやろうとしていたことには適していません。

2 つのリポジトリを結合する Powershell スクリプトの例を次に示します。

# Assume the current directory is where we want the new repository to be created
# Create the new repository
git init

# Before we do a merge, we have to have an initial commit, so we'll make a dummy commit
git commit --allow-empty -m "Initial dummy commit"

# Add a remote for and fetch the old repo
# (the '--fetch' (or '-f') option will make git immediately fetch commits to the local repo after adding the remote)
git remote add --fetch old_a <OldA repo URL>

# Merge the files from old_a/master into new/master
git merge old_a/master --allow-unrelated-histories

# Move the old_a repo files and folders into a subdirectory so they don't collide with the other repo coming later
mkdir old_a
dir -exclude old_a | %{git mv $_.Name old_a}

# Commit the move
git commit -m "Move old_a files into subdir"

# Do the same thing for old_b
git remote add -f old_b <OldB repo URL>
git merge old_b/master --allow-unrelated-histories
mkdir old_b
dir –exclude old_a,old_b | %{git mv $_.Name old_b}
git commit -m "Move old_b files into subdir"

明らかに、代わりに old_b を old_a (新しい結合リポジトリになる) にマージすることもできます。それを行う場合は、スクリプトを適切に変更します。

進行中のフィーチャー ブランチも引き継ぎたい場合は、次のようにします。

# Bring over a feature branch from one of the old repos
git checkout -b feature-in-progress
git merge -s recursive -Xsubtree=old_a old_a/feature-in-progress

これは、プロセスの唯一の非自明な部分です。これは、サブツリーのマージではなく、ターゲットの名前を変更したことを Git に伝え、Git がすべてを正しく並べるのに役立つ、通常の再帰的マージの引数です。

もう少し詳しい説明をここに書きました。

于 2013-01-22T23:57:18.230 に答える
7

使って見てください

git rebase --root --preserve-merges --onto

人生の早い段階で 2 つの歴史を結び付けます。

重複するパスがある場合は、それらを修正します

git filter-branch --index-filter

ログを使用するときは、「コピーをより困難に見つける」ことを確認してください

git log -CC

そうすれば、パス内のファイルの移動を見つけることができます。

于 2012-10-24T01:56:22.507 に答える
7

@Flimm thisのソリューションgit aliasを次のように変更しました( my に追加~/.gitconfig):

[alias]
 mergeRepo = "!mergeRepo() { \
  [ $# -ne 3 ] && echo \"Three parameters required, <remote URI> <new branch> <new dir>\" && exit 1; \
  git remote add newRepo $1; \
  git fetch newRepo; \
  git branch \"$2\" newRepo/master; \
  git checkout \"$2\"; \
  mkdir -vp \"${GIT_PREFIX}$3\"; \
  git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} \"${GIT_PREFIX}$3\"/; \
  git commit -m \"Moved files to '${GIT_PREFIX}$3'\"; \
  git checkout master; git merge --allow-unrelated-histories --no-edit -s recursive -X no-renames \"$2\"; \
  git branch -D \"$2\"; git remote remove newRepo; \
}; \
mergeRepo"
于 2016-09-06T09:24:11.447 に答える
3

この関数は、リモート リポジトリをローカル リポジトリ ディレクトリに複製します。

function git-add-repo
{
    repo="$1"
    dir="$(echo "$2" | sed 's/\/$//')"
    path="$(pwd)"

    tmp="$(mktemp -d)"
    remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')"

    git clone "$repo" "$tmp"
    cd "$tmp"

    git filter-branch --index-filter '
        git ls-files -s |
        sed "s,\t,&'"$dir"'/," |
        GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
        mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
    ' HEAD

    cd "$path"
    git remote add -f "$remote" "file://$tmp/.git"
    git pull "$remote/master"
    git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
    git remote remove "$remote"
    rm -rf "$tmp"
}

使い方:

cd current/package
git-add-repo https://github.com/example/example dir/to/save

知らせ。このスクリプトはコミットを書き換えることができますが、すべての作成者と日付を保存します。これは、新しいコミットが別のハッシュを持つことを意味し、変更をリモート サーバーにプッシュしようとすると、強制キーでのみ可能になり、サーバー上のコミットも書き換えられます。そのため、起動する前にバックアップを作成してください。

利益!

于 2017-04-11T08:24:06.847 に答える