Gitサブモジュールを使ったプロジェクトがあります。これはssh:// ... URLからのもので、コミットAです。コミットBはそのURLにプッシュされました。サブモジュールにコミットを取得させて変更します。
git submodule update
はこれを行うべきだと私は理解していますが、そうではありません。何もしません(出力なし、成功終了コード)。これが例です:
$ mkdir foo
$ cd foo
$ git init .
Initialized empty Git repository in /.../foo/.git/
$ git submodule add ssh://user@Host/git/mod mod
Cloning into mod...
user@Host's password: hunter2
remote: Counting objects: 131, done.
remote: Compressing objects: 100% (115/115), done.
remote: Total 131 (delta 54), reused 0 (delta 0)
Receiving objects: 100% (131/131), 16.16 KiB, done.
Resolving deltas: 100% (54/54), done.
$ git commit -m "Hello world."
[master (root-commit) 565b235] Hello world.
2 files changed, 4 insertions(+), 0 deletions(-)
create mode 100644 .gitmodules
create mode 160000 mod
# At this point, ssh://user@Host/git/mod changes; submodule needs to change too.
$ git submodule init
Submodule 'mod' (ssh://user@Host/git/mod) registered for path 'mod'
$ git submodule update
$ git submodule sync
Synchronizing submodule url for 'mod'
$ git submodule update
$ man git-submodule
$ git submodule update --rebase
$ git submodule update
$ echo $?
0
$ git status
# On branch master
nothing to commit (working directory clean)
$ git submodule update mod
$ ...
私はgit fetch mod
も試しましたが、これはフェッチをするように見えます(しかし、パスワードを要求していないのでできません!)が、git log
とgit show
は新しいコミットの存在を否定します。これまでのところ、私はモジュールをrm
nameして再追加したばかりですが、これは原則として間違っているだけでなく、実際には面倒です。
git submodule update
コマンドは実際に、サブプロジェクトがスーパープロジェクトのインデックスで既に指定されているコミットをチェックアウトするようにGitに指示します。リモートから利用可能な最新のコミットに update あなたのサブモジュールを使いたい場合は、サブモジュールで直接これを行う必要があります。
要約すると:
# get the submodule initially
git submodule add ssh://bla submodule_dir
git submodule init
# time passes, submodule upstream is updated
# and you now want to update
# change to the submodule directory
cd submodule_dir
# checkout desired branch
git checkout master
# update
git pull
# get back to your project root
cd ..
# now the submodules are in the state you want, so
git commit -am "Pulled down update to submodule_dir"
または、あなたが忙しい人なら:
git submodule foreach git pull Origin master
Git 1.8.2には、この動作を可能にする新しいオプション--remote
があります。ランニング
git submodule update --remote --merge
各サブモジュールのアップストリームから最新の変更を取得し、それらをマージして、サブモジュールの最新のリビジョンをチェックアウトします。として ドキュメント それを置く:
- リモート
このオプションはupdateコマンドに対してのみ有効です。スーパープロジェクトの記録済みSHA-1を使用してサブモジュールを更新する代わりに、サブモジュールのリモートトラッキングブランチのステータスを使用してください。
これは各サブモジュールでgit pull
を実行するのと同等です。
プロジェクトの親ディレクトリで次のコマンドを実行します。
git submodule update --init
あるいは再帰的なサブモジュールが走っているなら:
git submodule update --init --recursive
サブモジュールが更新されている間に、どういうわけかあなたがローカルサブモジュールディレクトリにローカルの変更を行っているため、これはまだうまくいかないことがあります。
ほとんどの場合、ローカルの変更はあなたがコミットしたいものではないかもしれません。サブモジュールなどでファイルが削除されたことが原因で発生する可能性があります。その場合は、ローカルサブモジュールディレクトリおよびプロジェクトの親ディレクトリでリセットを再実行します。
git submodule update --init --recursive
あなたのメインプロジェクトは、サブモジュールがあるべき特定のコミットを指しています。 git submodule update
が行うことは、初期化された各サブモジュールでそのコミットをチェックアウトすることです。サブモジュールは実際には独立したリポジトリです。サブモジュール内に新しいコミットを作成してそれを実行するだけでは不十分です。メインプロジェクトに新しいバージョンのサブモジュールを明示的に追加する必要もあります。
だから、あなたの場合は、サブモジュールの中で正しいコミットを見つけるべきです - それがマスターの先端であると仮定しよう:
cd mod
git checkout master
git pull Origin master
メインプロジェクトに戻ってサブモジュールをステージングし、それをコミットします。
cd ..
git add mod
git commit -m "Updating the submodule 'mod' to the latest version"
メインプロジェクトの新しいバージョンをプッシュしましょう。
git Push Origin master
これ以降、他の誰かがメインプロジェクトを更新すると、初期化されていると仮定して、彼らのgit submodule update
がサブモジュールを更新します。
この議論では、2つの異なるシナリオが混在しているようです。
シナリオ1
親リポジトリのサブモジュールへのポインタを使用して、親リポジトリが指している各サブモジュール内のコミットをチェックアウトします。おそらく最初にすべてのサブモジュールを反復処理し、これらをリモートから更新/プルした後です。
指摘したように、これは
git submodule foreach git pull Origin BRANCH
git submodule update
シナリオ2、私はOPが目指しているのはそれだと思う
1つまたは複数のサブモジュールで新しい処理が行われました。1)これらの変更を取得し、2)このサブモジュールのHEAD(最新)コミットを指すように親リポジトリを更新します。
これは
git submodule foreach git pull Origin BRANCH
git add module_1_name
git add module_2_name
......
git add module_n_name
git Push Origin BRANCH
あなたは例えばn個のサブモジュール全てにn個のパスをハードコードしなければならないので、あまり実用的ではない。親リポジトリのコミットポインタを更新するスクリプト。
クールなことは、サブモジュールの先頭を指すように(git addを使用して)親リポジトリのポインタを更新しながら、各サブモジュールを介して自動的に反復することです。
このために、私はこの小さなbashスクリプトを作りました:
git-update-submodules.sh
#!/bin/bash
APP_PATH=$1
shift
if [ -z $APP_PATH ]; then
echo "Missing 1st argument: should be path to folder of a git repo";
exit 1;
fi
BRANCH=$1
shift
if [ -z $BRANCH ]; then
echo "Missing 2nd argument (branch name)";
exit 1;
fi
echo "Working in: $APP_PATH"
cd $APP_PATH
git checkout $BRANCH && git pull --ff Origin $BRANCH
git submodule sync
git submodule init
git submodule update
git submodule foreach "(git checkout $BRANCH && git pull --ff Origin $BRANCH && git Push Origin $BRANCH) || true"
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
git commit -m "Updated $BRANCH branch of deployment repo to point to latest head of submodules"
git Push Origin $BRANCH
実行するには
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
精巧さ
まず最初に、$ BRANCH(2番目の引数)という名前のブランチがすべてのリポジトリに存在すると仮定します。これをもっともっと複雑にしてください。
最初のいくつかの節では、引数があることを確認します。それから私は親リポジトリの最新のものを引っ張ります(引っ張っているときはいつでも--ff(早送り)を使うのが好きです。
git checkout $BRANCH && git pull --ff Origin $BRANCH
新しいサブモジュールが追加されたか、まだ初期化されていない場合は、サブモジュールの初期化が必要になることがあります。
git submodule sync
git submodule init
git submodule update
それから私はすべてのサブモジュールを更新します/引っ張ります:
git submodule foreach "(git checkout $BRANCH && git pull --ff Origin $BRANCH && git Push Origin $BRANCH) || true"
まず第一に、私はいくつかのgitコマンドを&&
を使ってつなげています - 前のコマンドはエラーなしで実行しなければならないことを意味します。
(リモートで新しいものが見つかった場合は)プルに成功した後、マージコミットがクライアントに残っていないことを確認するためにPushを実行します。繰り返しますが、 if が実際に新しいものを持ってきた場合に限ります。
最後に、最後の|| true
はスクリプトがエラーで継続することを保証します。これをうまく機能させるには、反復のすべてを二重引用符で囲み、gitコマンドを括弧で囲む必要があります(演算子の優先順位)。
私のお気に入りの部分:
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
--quiet
を使用してすべてのサブモジュールを反復します。これにより、 'Entering MODULE_PATH'出力が削除されます。 'echo $path'
(一重引用符で囲む必要があります)を使用して、サブモジュールへのパスが出力に書き込まれます。
この相対的なサブモジュールパスのリストは、配列($(...)
)に取り込まれます - 最後にこれを繰り返し、git add $i
を実行して親リポジトリを更新します。
最後に、親リポジトリが更新されたことを説明するメッセージ付きのコミット。何もしなければ、このコミットはデフォルトで無視されます。これをOriginにプッシュすれば完了です。
私はjenkinsの仕事でこれを実行するスクリプトを持っています。そして、それはその後予定された自動化された展開につながります、そしてそれは魅力のように働きます。
これが誰かに役立つことを願っています。
サブモジュールを取得するためのプレーンでシンプルなもの:
git submodule update --init --recursive
そして今度はそれらを最新のマスターブランチに更新します(例えば):
git submodule foreach git pull Origin master
git pull --recurse-submodules
これは最新のコミットをすべて引っ張ります。
@Jasonはある意味で正しいですが、完全ではありません。
更新
登録されているサブモジュールを更新します。つまり、見つからないサブモジュールのクローンを作成し、それを含むリポジトリのインデックスで指定されたコミットをチェックアウトします。 --rebaseまたは--mergeが指定されていないか、キーサブモジュール$ name.updateがrebaseまたはmergeに設定されていない限り、これによってサブモジュールHEADが切り離されます。
それで、gitサブモジュールのアップデートはチェックアウトをします、しかし、事はそれが含まれているリポジトリのインデックスでコミットすることです。上流の新しいコミットをまだ知りません。それであなたのサブモジュールに行き、あなたが望むコミットを得てそしてメインレポジトリの中で更新されたサブモジュールの状態をコミットしそしてそれからgit submodule update
を実行してください
私の場合は、git
を最新のものに更新し、同時に不足しているファイルを再投入したいと思いました。
以下は不足しているファイルを復元しました(ここで言及されていないようです--force
のおかげで)、しかしそれはどんな新しいコミットも引き寄せませんでした:
git submodule update --init --recursive --force
これはしました:
git submodule update --recursive --remote --merge --force
あなたがホストブランチを知らないなら、これを作ります:
git submodule foreach git pull Origin $(git rev-parse --abbrev-ref HEAD)
それはmain gitの枝を得て、それからそれぞれのサブモジュールに対して同じ枝を引っ張ります。
これは、マスター上のすべてを最新のものに更新するための素晴らしいワンライナーです。
git submodule foreach 'git fetch Origin --tags; git checkout master; git pull' && git pull && git submodule update --init --recursive
最新のサブモジュールコミットの更新形式は次のようになります。
git submodule update --recursive --remote --merge --force
古い形式は次のとおりです。
git submodule foreach --quiet git pull --quiet Origin
を除いて...この2番目の形式は本当に "静か"ではありません。
commit a282f5a (= 129年1月12日) NguyễnTháiNgyc Duy(pclouds
) を参照してください。
( にマージされたJunio C Hamano - gitster
- in commit f1c9f6c 、2019年4月25日
submodule foreach
: "<command> --quiet
"が尊重されていないのを修正Robinはそれを報告した
git submodule foreach --quiet git pull --quiet Origin
もう本当に静かではありません。
fc1b924 (submodule
:portsubmodule
サブコマンド 'foreach
'からCへのシェル、2018年5月10日、Git v2.19.0-rc0)parseopt
は誤ってオプションを食べることはできません。"
git pull
"は、--quiet
が与えられていないかのように振る舞います。これは、
submodule--helper
内のparseopt
が両方の--quiet
オプションを、git-pull
ではなくforeachのオプションであるかのように解析しようとするために発生します。
解析されたオプションはコマンドラインから削除されました。ですので後で引っ張るときは、これだけを実行します。git pull Origin
サブモジュールヘルパーを呼び出すとき、 "
--
"の前に "git pull
"を追加すると、実際にはsubmodule--helper foreach
に属さないオプションを解析するためのparseopt
が停止します。安全対策として
PARSE_OPT_KEEP_UNKNOWN
は削除されました。parseopt
は未知のオプションを見たり、何か問題があったりしてはいけません。私がそれらを見ている間、カップル用法ストリング更新もあります。それまでの間、私は他のサブコマンドに "
--
"を追加して、 "$@
"をsubmodule--helper
に渡します。この場合の "$@
"はパスであり、--something-like-this
である可能性は低いです。
しかし、要点はまだ立っています、git-submodule
は、オプションとは何か、パスとは何かを解析し、分類しました。submodule--helper
は、git-submodule
によって渡されたパスが、たとえそれらが1つのように見えても、オプションと見なすべきではありません。