web-dev-qa-db-ja.com

サブフォルダーごとにリポジトリを分割し、すべての古いブランチを保持するgit

2つのディレクトリと複数のブランチを持つgitリポジトリがあります。それらを分割してすべてのブランチを作成したいと思います。

`-- Big-repo
    |-- dir1
    `-- dir2

Branches : branch1, branch2, branch3 ...

欲しいもの

Dir1とdir2を2つの別々のリポジトリとして分割し、両方のリポジトリにブランチbranch1、branch2 ...を保持したいと思います。

dir1
Branches : branch1, branch2, branch3 ...

dir2
Branches : branch1, branch2, branch3 ...

私が試したこと:

私はそれらを使用して2つのリポジトリに分割することができます

git subtree split -P dir1 -b dir1-only 
git subtree split -P dir2 -b dir2-only 

ただし、分離後にブランチは作成されません。

すべてのブランチを取得するには:

git checkout branch1 (in Big-repo)
git subtree split -p dir1 -b dir1-branch1

git checkout branch2 (in Big-repo)
git subtree split -p dir1 -b dir1-branch2

And Push these branches to newly created repo.

これにはより多くの手作業が必要であり、これを達成するための迅速な方法があると確信していますか?

何か案は???

28
Sridhar

短い答え

git filter-branch 必要な機能を正確に提供します。 --subdirectory-filterオプションを使用すると、subDirectoryの内容がディレクトリのルートにある新しいコミットのセットを作成できます。

git filter-branch --Prune-empty --subdirectory-filter subDirectory -- --branches

ウォークスルー

以下は、これを安全な方法で実行するための例です。独自のリポジトリ(この場合はdir1)に分離されるサブディレクトリごとにこれを実行する必要があります。

まず、リポジトリのクローンを作成して、変更を分離します。

git clone yourRemote dir1Clone
cd dir1Clone

複製されたリポジトリを準備するために、すべてのリモートブランチをローカルブランチとして再作成します。 *で始まるブランチは現在のブランチであるためスキップします。この場合、ヘッドレス状態であるため(no branch)と表示されます。

# move to a headless state
# in order to delete all branches without issues
git checkout --detach

# delete all branches
git branch | grep --invert-match "*" | xargs git branch -D

すべてのリモートブランチをローカルで再作成するには、git branch --remotesの結果を確認します。 ->を含むものはブランチではないため、スキップします。

# get all local branches for remote
git branch --remotes --no-color | grep --invert-match "\->" | while read remote; do
    git checkout --track "$remote"
done

# remove remote and remote branches
git remote remove Origin

最後に、filter-branchコマンドを実行します。これにより、dir1サブディレクトリにアクセスするすべてのコミットで新しいコミットが作成されます。このサブディレクトリにもアクセスするすべてのブランチが更新されます。出力には、更新されていないすべての参照が一覧表示されます。これは、dir1にまったく触れていないブランチの場合です。

# Isolate dir1 and recreate branches
# --Prune-empty removes all commits that do not modify dir1
# -- --all updates all existing references, which is all existing branches
git filter-branch --Prune-empty --subdirectory-filter dir1 -- --all

この後、リポジトリのルートにdir1を持つ新しいコミットのセットが作成されます。リモコンを追加して新しいコミットをプッシュするか、これらをすべて新しいリポジトリとして使用します。

リポジトリのサイズが気になる場合の追加の最後のステップとして:

リポジトリを更新したすべてのブランチに元のリポジトリのすべてのオブジェクトが残っている場合でも、ref-logを介してのみ到達できます。これらの読み取りを削除したい場合 コミットをガベージコレクションする方法

いくつかの追加リソース:

43
LopSae

このスクリプトは私のために仕事をします:

#!/bin/bash

set -e

if [ -z "$3" ]; then
        echo "usage: $0 /full/path/to/repository path/to/splitfolder/from/repository/root new_Origin"
        exit
fi

repoDir=$1
folder=$2
newOrigin=$3

cd $repoDir

git checkout --detach
git branch | grep --invert-match "*" | xargs git branch -D

for remote in `git branch --remotes | grep --invert-match "\->"`
do
        git checkout --track $remote
        git add -vA *
        git commit -vam "Changes from $remote" || true
done

git remote remove Origin
git filter-branch --Prune-empty --subdirectory-filter $folder -- --all

#Prune old objects
rm -rf .git/refs/original/*
git reflog expire --all --expire-unreachable=0
git repack -A -d
git Prune

#upload to new remote
git remote add Origin $newOrigin
git Push Origin master

for branch in `git branch | grep -v '\*'`
do
        git Push Origin $branch
done
6
Arohi