web-dev-qa-db-ja.com

浅いgitサブモジュールを作成するには?

浅いサブモジュールを持つことは可能ですか?私はそれぞれ長い歴史を持ついくつかのサブモジュールを持つスーパープロジェクトを持っているので、そのすべての歴史をドラッグすることは不必要に大きくなります。

私が見つけたのは この未回答のスレッド だけです。

git-submoduleをハックする を実装するだけですか?

124

今後の git1.8.4(2013年7月) の新機能:

git submodule update」は、オプションでサブモジュールリポジトリを浅く複製できます。

(そしてgit 2.10 Q3 2016では、git config -f .gitmodules submodule.<name>.shallow trueで記録できます。
この回答の最後をご覧ください)

commit 275cd184d52b5b81cb89e4ec33e540fb2ae61c1f を参照してください:

「git submodule」の追加および更新コマンドに--depthオプションを追加し、クローンコマンドに渡されます。これは、サブモジュールが巨大であり、最新のコミット以外に本当に興味がない場合に便利です。

テストが追加され、「サブモジュールの更新はpwdのシンボリックリンクを処理できます」のテストファイルの残りの部分に適合するように、インデントの調整が行われました。

サインオフ:Fredrik Gustafsson <[email protected]>
Acked-by:Jens Lehmann <[email protected]>

これはこれが機能することを意味します:

git submodule add --depth 1 -- repository path
git submodule update --depth -- [<path>...]

と:

--depth::

このオプションは、addおよびupdateコマンドに有効です。
指定されたリビジョン数に切り捨てられた履歴を持つ「浅い」クローンを作成します。


atwymanコメント内の を追加します:

私が知る限り、このオプションはmasterを非常に厳密に追跡しないサブモジュールには使用できません。深さ1を設定すると、submodule updateは、目的のサブモジュールコミットが最新のマスターである場合にのみ成功します。 それ以外の場合は、「fatal: reference is not a treeを取得します。

それは本当です。
つまり、git 2.8(2016年3月)までです。 2.8では、SHA1がリモートリポジトリHEADの1つから直接到達可能である場合でも、submodule update --depthが成功する可能性がもう1つあります。

Stefan Beller(stefanbeller による commit fb43e312016年2月24日)を参照してください。
ヘルプ: Junio C Hamano(gitster
Junio C Hamano-gitster- in commit 9671a76 、2016年2月26日)

サブモジュール:sha1を直接取得して、必要なsha1を取得しようとする

Gerritのサブモジュールも更新する変更を確認する場合、一般的な確認方法は、パッチをダウンロードしてチェリーピックしてローカルでテストすることです。
ただし、ローカルでテストする場合、サブモジュール内の対応するコミットはまだプロジェクト履歴の一部ではなく、提案された変更であるため、「git submodule update」は正しいサブモジュールsha1のフェッチに失敗する場合があります。

$sha1がデフォルトフェッチの一部ではなかった場合、$sha1を直接フェッチしようとします。ただし、一部のサーバーはsha1による直接フェッチをサポートしていないため、git-fetchがすぐに失敗します。
まだ見つからないsha1がチェックアウト段階の後半で失敗するため、ここで失敗する可能性があります。


[〜#〜] mvg [〜#〜] が指摘する コメント内の から commit fb43e31 (git 2.9、2016年2月)

commit fb43e31 はSHA1 idで欠落しているコミットを要求しているように思われるので、サーバー上のuploadpack.allowReachableSHA1InWantおよびuploadpack.allowTipSHA1InWant設定はおそらくこれが機能するかどうかに影響します。
私は 今日のgitリストへの投稿 を書いて、いくつかのシナリオ、つまりコミットもタグである場合、浅いサブモジュールの使用をよりうまく機能させる方法を指摘しました。
待って見てみましょう。

これが、fb43e31がデフォルトのブランチのフェッチ後に特定のSHA1のフェッチをフォールバックにした理由だと思います。
それにもかかわらず、「-depth 1」の場合、早めに中止するのが理にかなっていると思います。リストされたrefのいずれも要求されたrefと一致せず、SHA1による問い合わせがサーバーによってサポートされていないどちらの方法でもサブモジュールの要件を満たすことができないため、何かをフェッチしても意味がありません。


2016年8月更新(3年後)

Git 2.10(Q3 2016)では、次のことができるようになります

 git config -f .gitmodules submodule.<name>.shallow true

詳細については、「 余分な重みのないGitサブモジュール 」を参照してください。


Git 2.13(2017年第2四半期) commit 8d3047c (2017年4月19日)によって Sebastian Schuberth(sschuberth を追加します。
Sebastian Schuberth-sschuberth- in commit 8d3047c 、2017年4月20日)

このサブモジュールのクローンは、浅いクローンとして実行されます(履歴の深さ1)

ただし、 Ciro Santilliコメントに を追加します(詳細は 彼の回答

shallow = true上の.gitmodulesは、ターゲットコミットがブランチによってポイントされている場合でも、--recurse-submodulesbranch = mybranchに配置している場合でも、.gitmodulesを使用する場合、リモートのHEAD 。


Git 2.20(2018年第4四半期)では、サブモジュールのサポートが改善され、HEAD:.gitmodulesファイルが作業ツリーにない場合に.gitmodulesのblobから読み取るように更新されました。

commit 2b1257ecommit 76e9bdc (2018年10月25日)、および commit b5c259fcommit 23dd8f5commit b2faad4 を参照してください_、 commit 2502ffccommit 996df4dcommit d1b13dfcommit 45f5efcommit bcbc78 (2018年10月5日)by Antonio Ospite(ao2
Junio C Hamano-gitster- in commit abb4824 、2018年11月13日)

submodule:作業ツリーにない場合の.gitmodulesの読み取りをサポート

.gitmodulesファイルが作業ツリーで利用できない場合、インデックスと現在のブランチのコンテンツを使用してみてください。
これは、ファイルがリポジトリの一部であるが、何らかの理由で、たとえばスパースチェックアウトのためにチェックアウトされない場合を対象としています。

これにより、少なくとも「git submodule」コマンドを使用できるようになります。このコマンドは、作業ツリーに完全に入力することなく、_(readgitmodules構成ファイルを読み取ります。

.gitmodulesへの書き込みでは、ファイルをチェックアウトする必要があるため、config_set_in_gitmodules_file_gentlyを呼び出す前にファイルをチェックアウトする必要があります。

git-submodule.sh::cmd_add()にも同様のチェックを追加して、git submodule addが安全に書き込み可能でない場合に「.gitmodules」コマンドが最終的に失敗することを予測します。これにより、コマンドがリポジトリを誤った状態のままにするのを防ぎます(たとえば、サブモジュールリポジトリは複製されましたが、.gitmodulesが失敗したためconfig_set_in_gitmodules_file_gentlyは更新されませんでした)。

さらに、config_from_gitmodules()はグローバルオブジェクトストアにアクセスするため、グローバルオブジェクトストアへの同時アクセスから関数を呼び出すすべてのコードパスを保護する必要があります。
現在、これはbuiltin/grep.c::grep_submodules()でのみ発生するため、grep_read_lock()を含むコードを呼び出す前にconfig_from_gitmodules()を呼び出してください。

注:この新しい機能がまだ正しく機能しないまれなケースが1つあります。作業ツリーに.gitmodulesのないネストされたサブモジュールです。

114
VonC

Git 2.9. サブモジュールの浅いクローンを直接サポートするため、次のように呼び出すことができます:

git clone url://to/source/repository --recursive --shallow-submodules
22
KindDragon

次の Ryanの答え すべてのサブモジュールを反復処理し、それらを浅く複製するこの単純なスクリプトを思いつくことができました。

#!/bin/bash
git submodule init
for i in $(git submodule | sed -e 's/.* //'); do
    spath=$(git config -f .gitmodules --get submodule.$i.path)
    surl=$(git config -f .gitmodules --get submodule.$i.url)
    git clone --depth 1 $surl $spath
done
git submodule update
15

Git-submodule "source"を読むと、git submodule addは、すでにリポジトリが存在するサブモジュールを処理できます。その場合...

$ git clone $remote1 $repo
$ cd $repo
$ git clone --depth 5 $remotesub1 $sub1
$ git submodule add $remotesub1 $sub1
#repeat as necessary...

必要なコミットがサブモジュールリポジトリにあることを確認する必要があるため、適切な--depthを設定してください。

編集:複数の手動サブモジュールクローンに続いて1つの更新を行うことができます。

$ git clone $remote1 $repo
$ cd $repo
$ git clone --depth 5 $remotesub1 $sub1
#repeat as necessary...
$ git submodule update
8
Ryan Graham

Git 2.14.1以降のバグのある/予期しない/迷惑な動作の概要

  1. _shallow = true_の_.gitmodules_は、リモートサブモジュールのHEADが必要なコミットを指している場合、ターゲットコミットがブランチによってポイントされている場合でも、_git clone --recurse-submodules_にのみ影響します。 _branch = mybranch_にも_.gitmodules_を配置した場合。

    ローカルテストスクリプトHEADがデフォルトのブランチリポジトリ設定によって制御されるGitHub 2017-11での同じ動作:

    _git clone --recurse-submodules https://github.com/cirosantilli/test-shallow-submodule-top-branch-shallow
    cd test-shallow-submodule-top-branch-shallow/mod
    git log
    # Multiple commits, not shallow.
    _
  2. _git clone --recurse-submodules --shallow-submodules_は、コミットがブランチまたはメッセージのタグで参照されていない場合に失敗します:_error: Server does not allow request for unadvertised object_。

    ローカルテストスクリプト 。 GitHubでの同じ動作:

    _git clone --recurse-submodules --shallow-submodules https://github.com/cirosantilli/test-shallow-submodule-top-sha
    # error
    _

    また、私はメーリングリストで尋ねました: https://marc.info/?l=git&m=151863590026582&w=2 そして返信は:

    理論的には、これは簡単なはずです。 :)

    残念ながら、実際にはそれほどではありません。これは、クローン作成がブランチの最新のチップ(通常はマスター)を取得するだけだからです。 cloneには、必要なsha1を正確に指定するメカニズムはありません。

    ワイヤプロトコルは、正確なsha1を要求することをサポートしているため、これをカバーする必要があります。 (注意:githubがAFAICTを持たないuploadpack.allowReachableSHA1InWantをサーバーオペレーターが有効にしている場合にのみ機能します)

    git-fetchは任意のsha1をフェッチできるため、回避策として、「git submodule update」を使用して再帰クローンの後にフェッチを実行できます。初期クローンの後にフェッチを使用するためです。

TODOテスト: _allowReachableSHA1InWant_

サブモジュールの正規の場所はリモートですか?もしそうなら、一度クローンを作成しても大丈夫ですか?言い換えれば、頻繁にサブモジュール(再)クローンの帯域幅が浪費されているという理由だけで、浅いクローンが必要ですか?

浅いクローンでローカルディスク領域を節約したい場合、Ryan Grahamの答えは良い方法のように思えます。リポジトリが浅くなるように手動でクローンを作成します。役立つと思われる場合は、git submoduleを適応させてサポートしてください。 リスト にメールを送信します(実装のアドバイス、インターフェースに関する提案など)。私の意見では、建設的な方法でGitを強化したい潜在的な貢献者を非常に支持しています。

各サブモジュールの完全なクローンを1つ作成することに問題がない場合(さらに最新の状態に保つために後でフェッチする)、--referencegit submodule updateオプションを使用してみてください(Git 1.6.4および後で)ローカルオブジェクトストアを参照する(たとえば、正規のサブモジュールリポジトリの--mirrorクローンを作成し、サブモジュールで--referenceを使用してこれらのローカルクローンを指す)。 git clone --referenceを使用する前に、必ずgit clone --shared/--referenceについて読んでください。ミラーの参照に関する唯一の問題は、非早送りの更新を取得する場合です(ただし、reflogsを有効にして有効期限ウィンドウを拡張し、問題を引き起こす可能性のある放棄されたコミットを保持することができます)。限り問題はないはずです

  • ローカルサブモジュールをコミットしない、または
  • 標準リポジトリが公開する可能性のある非早送りによってぶら下がっているコミットは、ローカルサブモジュールコミットの先祖ではありません。
  • 正規のサブモジュールリポジトリで公開される可能性のある非早送りに基づいて、ローカルサブモジュールのコミットをリベースすることに熱心です。

このようなもので、作業ツリーでローカルサブモジュールコミットを実行する可能性がある場合は、チェックアウトされたサブモジュールによって参照される重要なオブジェクトがそうでないことを確認する自動システムを作成することをお勧めします。ミラーリポジトリにぶら下がっています(見つかった場合は、それらを必要とするリポジトリにコピーします)。

また、git cloneのマンページにあるように、これらの影響を理解していない場合は、--referenceを使用しないでください。

# Full clone (mirror), done once.
git clone --mirror $sub1_url $path_to_mirrors/$sub1_name.git
git clone --mirror $sub2_url $path_to_mirrors/$sub2_name.git

# Reference the full clones any time you initialize a submodule
git clone $super_url super
cd super
git submodule update --init --reference $path_to_mirrors/$sub1_name.git $sub1_path_in_super
git submodule update --init --reference $path_to_mirrors/$sub2_name.git $sub2_path_in_super

# To avoid extra packs in each of the superprojects' submodules,
#   update the mirror clones before any pull/merge in super-projects.
for p in $path_to_mirrors/*.git; do GIT_DIR="$p" git fetch; done

cd super
git pull             # merges in new versions of submodules
git submodule update # update sub refs, checkout new versions,
                     #   but no download since they reference the updated mirrors

または、--referenceの代わりに、ローカルミラーをサブモジュールのソースとして使用することにより、ミラークローンをgit cloneのデフォルトのハードリンク機能と組み合わせて使用​​できます。新しいスーパープロジェクトのクローンでは、git submodule initを実行し、.git/configのサブモジュールURLを編集してローカルミラーを指すようにしてから、git submodule updateを実行します。ハードリンクを取得するには、既存のチェックアウト済みサブモジュールを複製する必要があります。ミラーに一度ダウンロードするだけで帯域幅を節約し、それらからローカルにチェックアウトされたサブモジュールにフェッチします。ハードリンクはディスク領域を節約します(ただし、フェッチはチェックアウトされたサブモジュールのオブジェクトストアの複数のインスタンス間で蓄積され、複製される傾向があります。ミラーからチェックアウトされたサブモジュールを定期的に再クローンして、ディスク領域の節約を取り戻すことができますハードリンク)。

2
Chris Johnsen

特定のリビジョン/変更セットでgitリポジトリをクローンする方法 への参照

サブモジュール参照がマスターから離れているときに問題のない単純なスクリプトを作成しました

git submodule foreach --recursive 'git rev-parse HEAD | xargs -I {} git fetch Origin {} && git reset --hard FETCH_HEAD'

このステートメントは、サブモジュールの参照バージョンをフェッチします。

高速ですが、サブモジュールで編集をコミットすることはできません(事前に非浅いフェッチを行う必要があります https://stackoverflow.com/a/17937889/3156509

略さずに:

#!/bin/bash
git submodule init
git submodule foreach --recursive 'git rev-parse HEAD | xargs -I {} git fetch Origin {} && git reset --hard FETCH_HEAD'
git submodule update --recursive
1
Beeno Tung

サブモジュールの特定のリビジョン/変更セットでスナップショットを作成するため、サブモジュールの浅いクローンは完璧です。 WebサイトからZipをダウンロードするのは簡単なので、スクリプトを試しました。

#!/bin/bash
git submodule deinit --all -f
for value in $(git submodule | Perl -pe 's/.*(\w{40})\s([^\s]+).*/\1:\2/'); do
  mysha=${value%:*}
  mysub=${value#*:}
  myurl=$(grep -A2 -Pi "path = $mysub" .gitmodules | grep -Pio '(?<=url =).*/[^.]+')
  mydir=$(dirname $mysub)
  wget $myurl/archive/$mysha.Zip
  unzip $mysha.Zip -d $mydir
  test -d $mysub && rm -rf $mysub
  mv $mydir/*-$mysha $mysub
  rm $mysha.Zip
done
git submodule init

git submodule deinit --all -fは、スクリプトを再利用可能にするサブモジュールツリーをクリアします。

git submoduleは、.gitmodulesの同じ文字に対応するパスが後に続く40文字のsha1を取得します。 Perlを使用して、コロンで区切られたこの情報を連結し、変数変換を使用して値をmyshamysubに分離します。

これらは重要なキーです。sha1をダウンロードする必要があり、.gitmodulesのurlを関連付けるパスが必要だからです。

典型的なサブモジュールエントリが与えられた場合:

[submodule "label"]
    path = localpath
    url = https://github.com/repository.git

path =myurlキーは、値を取得するために2行後に見えます。この方法は一貫して機能せず、改良が必要な場合があります。 url grepは、最後の.gitおよび/までのすべてと一致することにより、残りの.型参照を除去します。

mydirは、mysubから最後の/nameを差し引いたもので、サブモジュール名に至るまでのディレクトリになります。

次は、ダウンロード可能なZipアーカイブURLの形式のwgetです。これは将来変更される可能性があります。

ファイルをmydirに解凍します。これは、サブモジュールパスで指定されたサブディレクトリになります。結果のフォルダーは、url-sha1の最後の要素になります。

サブモジュールパスで指定されたサブディレクトリが存在するかどうかを確認し、削除して、抽出されたフォルダの名前を変更できるようにします。

mvは、sha1を含む抽出されたフォルダーの名前を正しいサブモジュールパスに変更します。

ダウンロードしたZipファイルを削除します。

サブモジュールの初期化

これは、ソリューションというよりも、WIPの概念実証です。動作すると、指定されたチェンジセットにあるサブモジュールの浅いクローンが作成されます。

リポジトリがサブモジュールを別のコミットにリホームする場合は、スクリプトを再実行して更新します。

このようなスクリプトが役立つのは、ソースプロジェクトの非共同ローカルビルドの場合だけです。

1
noabody

すべてのプロジェクトが実行するわけではないが、最新のEdgeで実行されていない場合のために、わずかに異なるバージョンを作成しました。標準のサブモジュールの追加は機能せず、上記のスクリプトも機能しませんでした。そこで、タグrefのハッシュルックアップを追加し、ハッシュルックアップがない場合は、完全なクローンにフォールバックします。

#!/bin/bash
git submodule init
git submodule | while read hash name junk; do
    spath=$(git config -f .gitmodules --get submodule.$name.path)
    surl=$(git config -f .gitmodules --get submodule.$name.url)
    sbr=$(git ls-remote --tags $surl | sed -r "/${hash:1}/ s|^.*tags/([^^]+).*\$|\1|p;d")
    if [ -z $sbr ]; then
        git clone $surl $spath
    else
        git clone -b $sbr --depth 1 --single-branch $surl $spath
    fi
done
git submodule update 
1
sfossen