web-dev-qa-db-ja.com

gitリポジトリ内の既存のディレクトリをgitサブモジュールにする方法

Git-submodulesについて非常に混乱しています。

基本的に私の問題は、_~/main-project/submodule_がサブモジュールであることをgitに理解できないことです。


gitサブモジュールの使用経験があります:
dotfiles repository で_~/dotfiles-repo_に.gitmodulesファイルを作成し、そこにパスとURLを追加しました。それ以来、サブモジュール内のファイルに変更を加えて_git status_を実行すると、次のようなものが得られます:.vim/bundle/auto-complete (new commits) # in red

_.gitmodules_ファイルを_~/main-project_に作成しましたが、

  • _~/main-project/submodule_に変更を加え、その変更をプッシュしても、_git status_を_~/main-project_で実行すると、<submodule> (new commits) # in redのような同様の応答が返されません。 それらのディレクトリで行われた変更を取得するだけです
  • これらのディレクトリのgithubにあるフォルダのリンクをクリックすると、リポジトリ自体にリダイレクトされませんが、同じリポジトリにとどまります。

    1. 多分私は全体のポイントを見逃している。サブモジュールの主な機能は何ですか?
    2. なぜgitは dotfilesリポジトリ のサブモジュールを理解しますが、 他のリポジトリ のサブモジュールを理解しないのですか?
    3. _~/main-project/submodule_内のファイルをインデックスに追加するように既にgitに指示しているからでしょうか?

この質問 を読んだので、私は この答え に至りましたが、_git-subtree_が必要かどうかわかりません。変更を元に戻すのが難しいかもしれないことはしたくありません。

編集: これは重複した解決策を提案しました も機能しませんでした。_Updates were rejected because the remote contains work that you do not have locally_というエラーを受け取りました。 @ GabLeRoux は、実際に_<repo-A>_を_<repo-B>_のURLにプッシュするように指示したようです。

28
Doron Behar

ソリューションは非常に簡単です。 here から抽出されました。

  1. git rm submodule-dir
    これはgitがsubmodule-dirで追跡していたすべてのファイルを削除します
  2. rm -rf submoduledir
    これは、gitがそれらを無視したため、submodule-dirに残っていた可能性のある他のすべてのファイルを削除します。
  3. 次に、インデックスからファイルを削除するためにコミットする必要があります。
    git commit
    コミット後、submodul-dirでgitが追跡したファイルと追跡しなかったファイルを削除しました。それでは、次の作業を行います。
  4. git submodule add <remote-path-to-submodule>
    これはサブモジュールを再追加しますが、真のサブモジュールとして追加します。
  5. この時点で、.gitmodulesをチェックし、サブモジュールが正常に追加されたかどうかを確認することをお勧めします。私の場合、すでに.gitmodulesファイルがあったので、修正する必要がありました。

編集

v2.12.0-rc であり、 this commit の後、git submodule absorbgitdirsを受け取りました。これは、この質問を投稿したときにまさに必要でした。

これが docs このコマンドの状態です:

サブモジュールのgitディレクトリがサブモジュール内にある場合、サブモジュールのgitディレクトリをスーパープロジェクト$GIT_DIR/modulesパスに移動し、core.worktreeを設定してを追加してgitディレクトリとその作業ディレクトリを接続します。スーパープロジェクトのgitディレクトリに埋め込まれたgitディレクトリを指すgitファイル。

そのため、@ DomQと私が以前の回答で提案したように最初からやり直す代わりに、次を実行するだけで追加できます。

  1. サブモジュールをインデックスから削除せずに、サブモジュールのURLを.gitmodulesおよび.git/configに追加します。
    git submodule add <url> <path>
  2. サブモジュールの$GIT_DIRディレクトリ(通常のリポジトリでは.git)を.git/modules/<path>に移動します
    git submodule absorbgitdirs <path>
27
Doron Behar

基本的に最初からやり直すふりをするよりも良い方法はありません

  1. どこでもすべてがコミットされていることを確認する
  2. サブリポジトリを邪魔にならない場所に移動する
  3. git submodule addサブリポジトリのリモートから
  4. cd mysubmodule
  5. git fetch ../wherever/you/stashed/the/sub-repository/in/step-1
  6. git merge FETCH_HEAD

これがなぜそうなのかを説明するために、 git-submodule(1) マニュアルページから収集できるものよりも、どのサブモジュールareが必要かをより深く理解するよりも、または、Gitブックの 関連の章でも )。 このブログ投稿 でさらに詳細な説明を見つけましたが、その投稿は少し長いので、ここでそれらを自由に要約します。

低レベルでは、gitサブモジュールは次の要素で構成されます。

  • サブモジュールツリーの上部にある コミットオブジェクト
  • (最新バージョンのGit)サブモジュールのGitオブジェクトをホストする.git/modulesのサブディレクトリ、
  • .gitmodules構成ファイルのエントリ。

コミットオブジェクトは、親ツリーオブジェクトに含まれています(より正確には、SHA1によって参照されます)。 通常 は逆のことが起こるため、これは異常ですが、サブモジュールでコミットを実行した後にメインリポジトリのgit statusにディレクトリが表示される理由を説明します。 いくつかの実験git ls-treeで作成して、このコミットオブジェクトをより詳細に観察することもできます。

.git/modulesのサブディレクトリは、サブモジュールの.gitサブディレクトリを表します。そして実際、サブモジュールには.git行を使用して前者を指すgitdir:fileがあります。これは、Gitのバージョン1.7.8以降のデフォルトの動作 です 。別の.gitディレクトリを保持しているだけですべてが機能しない理由はわかりません。ただし、リリースノートに記載されている場合を除き、サブモジュールを持つブランチとそうでないブランチを切り替えるときに問題が発生する可能性があります't。

.gitmodulesファイルは、git submodule update --remoteおよび友人がプルするURLを提供します。これは明らかに、メインリポジトリのリモートのセットとは異なります。また、.gitmodulesコマンドと、それをバックグラウンドで呼び出す他のコマンドによって、.git/configの一部がgit submodule syncにコピーされることに注意してください。

.gitmodules + .git/config、および.git/modules + mysubmodule/.git(および実際にはgit submodule absorbgitdirs(後者の場合)、実際には、ツリー内コミットオブジェクトのみを作成するための磁器はありません。したがって、上記の変更を移動+再実行することにより提案されたソリューション。

3
DomQ

質問に順番に回答するには:

  1. GitHubによると、サブモジュールの 目的 。機能的には、親リポジトリによってバージョン管理されている子リポジトリ(他のファイルとほとんど同じように扱うことができる)を概念化するように設計されています。親は現在のコミットを追跡しますコンテンツではなくサブモジュール(子リポジトリ)のID
  2. リポジトリのインデックスにファイルをすでに追加しているためである可能性が最も高いです。その場合、解決策はgit rm --cached submodule-name/。次に、中間コミットを作成してから、フォルダーをリポジトリーとして追加しますgit add submodule-name(サブモジュールの場合、サブモジュール名の後に末尾のスラッシュがないことに注意してください)。
  3. はい :)

あなたが言及した answer は、コミットの履歴も修正するかもしれません:

  1. 利点

そのフォルダーは、将来のコミットだけでなく、すべてのコミット履歴でサブモジュールとして扱われます。これにより、フォルダのように扱われた以前のバージョンにチェックアウトする場合の複雑さを回避できます。ブランチの先端に戻ると、サブモジュールも入力し、最新のコミットをチェックアウトして、すべてのファイル(作業ディレクトリから削除される可能性がある)を復元する必要があるため、これは複雑です。これは、最新のコミットに対して何らかの再帰的なチェックアウトを行うことで回避できます。

  1. 欠点

コミット履歴が変更された場合、他のすべてのコントリビューターは、マージの競合またはさらに悪化するため、プロジェクトを再クローンする必要があります。問題をコミットしてプロジェクトに再導入します。

1
reubenjohn