web-dev-qa-db-ja.com

フォルダーからサブモジュールリポジトリを作成し、そのgitコミット履歴を保持します

特定の方法で他のWebアプリケーションを探索するWebアプリケーションがあります。 demosフォルダーにいくつかのWebデモが含まれており、デモの1つには独自のリポジトリが必要です。このデモアプリケーション用に別のリポジトリを作成し、それを サブパッケージ サブモジュール コミット履歴を失うことなくメインリポジトリから。

リポジトリのフォルダ内のファイルからコミット履歴を保持し、そこからリポジトリを作成し、代わりに サブモジュール として使用することは可能ですか?

94
GabLeRoux

詳細なソリューション

Npmを使用したgitサブモジュールの簡単な代替策については、この回答の最後にあるメモ(最後の段落)を参照してください;)

次の回答では、リポジトリからフォルダーを抽出し、そこからgitリポジトリーを作成し、フォルダーの代わりに submodule として含める方法を知っています。

Gerg Bayerの記事 Gitリポジトリから別のGitリポジトリへのファイルの移動、履歴の保持

最初は次のようなものがあります。

<git repository A>
    someFolders
    someFiles
    someLib <-- we want this to be a new repo and a git submodule!
        some files

以下の手順では、このsomeLib<directory 1>と呼びます。

最後に、次のようなものがあります。

<git repository A>
    someFolders
    someFiles
    @submodule --> <git repository B>

<git repository B>
    someFolders
    someFiles

他のリポジトリのフォルダーから新しいgitリポジトリーを作成します

ステップ1

分割するリポジトリの新しいコピーを取得します。

git clone <git repository A url>
cd <git repository A directory>

ステップ2

現在のフォルダが新しいリポジトリになるため、現在のリモートを削除します。

git remote rm Origin

ステップ3

目的のフォルダーの履歴を抽出してコミットします

git filter-branch --subdirectory-filter <directory 1> -- --all

これで、リポジトリのルートにdirectory 1のファイルを含むgitリポジトリがあり、関連するすべてのコミット履歴があります。

ステップ4

オンラインリポジトリを作成し、新しいリポジトリをプッシュします!

git remote add Origin <git repository B url>
git Push

最初のプッシュのためにupstreamブランチを設定する必要があるかもしれません

git Push --set-upstream Origin master

Clean <git repository A>(オプション、コメントを参照)

<git repository B>から<git repository A>のトレース(ファイルとコミット履歴)を削除したいので、このフォルダーの履歴は一度だけです。

これは、 githubからの機密データの削除 に基づいています。

新しいフォルダーに移動して

git clone <git repository A url>
cd <git repository A directory>
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <directory 1> -r' --Prune-empty --tag-name-filter cat -- --all

<directory 1>を削除するフォルダーに置き換えます。 -rは、指定されたディレクトリ内で再帰的に実行します:)。 Origin/master--forceにプッシュします

git Push Origin master --force

ボスステージ(下記の注を参照)

サブモジュール<git repository B>から<git repository A>に作成します

git submodule add <git repository B url>
git submodule update
git commit

すべてが期待どおりに機能したかどうかを確認し、Push

git Push Origin master

注意

このすべてを行った後、私の場合、 npm を使用して独自の依存関係を管理する方が適切であることに気付きました。 git urlとバージョンを指定できます。 package.json git urlsをdependencies として参照してください。

この方法で行う場合、要件として使用するリポジトリはnpmモジュールである必要があるため、package.jsonファイルが含まれている必要がありますまたは、次のエラーが表示されます:Error: ENOENT, open 'tmp.tgz-unpack/package.json'

tldr(代替ソリューション)

npm および git urls を使用して依存関係を管理する方が簡単な場合があります。

  • フォルダを新しいリポジトリに移動する
  • 両方のリポジトリ内でnpm initを実行します
  • 依存関係をインストールする場所でnpm install --save git://github.com/user/project.git#commit-ishを実行します
165
GabLeRoux

@GabLeRouxによるソリューションは、ブランチと関連するコミットをつぶします。

これらの余分なブランチとコミットをすべてクローンして保持する簡単な方法:

1-このgitエイリアスがあることを確認してください

git config --global alias.clone-branches '! git branch -a | sed -n "/\/HEAD /d; /\/master$/d; /remotes/p;" | xargs -L1 git checkout -t'

2-リモートのクローン、すべてのブランチのプル、リモートの変更、ディレクトリのフィルタリング、プッシュ

git clone [email protected]:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm Origin
git remote add Origin [email protected]:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git Push --all
git Push --tags
6
oodavid

GabLeRouxのソリューションは、git lfsを使用し、デタッチしたいディレクトリの下に大きなファイルがある場合を除いて、うまく機能します。その場合、ステップ3の後、すべての大きなファイルは、実際のファイルではなくポインターファイルのままになります。おそらく、フィルター分岐プロセスで.gitattributesファイルが削除されたためだと思います。

これを実現するために、私は次の解決策が私のために働くことを発見しました:

cp .gitattributes .git/info/attributes

Git lfsが大きなファイルを追跡するために使用する.gitattributes.git/ディレクトリにコピーして、削除されないようにします。

新しいブランチにgit lfsを使用したい場合は、フィルターブランチが完了したときに.gitattributesを忘れずに戻すことを忘れないでください:

mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m 'added back .gitattributes'
2
ls.