web-dev-qa-db-ja.com

Gitサブモジュールを最新のコミット元に更新

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 loggit showは新しいコミットの存在を否定します。これまでのところ、私はモジュールをrmnameして再追加したばかりですが、これは原則として間違っているだけでなく、実際には面倒です。

719
Thanatos

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
1231
Jason

Git 1.8.2には、この動作を可能にする新しいオプション--remoteがあります。ランニング

git submodule update --remote --merge

各サブモジュールのアップストリームから最新の変更を取得し、それらをマージして、サブモジュールの最新のリビジョンをチェックアウトします。として ドキュメント それを置く:

- リモート

このオプションはupdateコマンドに対してのみ有効です。スーパープロジェクトの記録済みSHA-1を使用してサブモジュールを更新する代わりに、サブモジュールのリモートトラッキングブランチのステータスを使用してください。

これは各サブモジュールでgit pullを実行するのと同等です。

377
David Z

プロジェクトの親ディレクトリで次のコマンドを実行します。

git submodule update --init 

あるいは再帰的なサブモジュールが走っているなら:

git submodule update --init --recursive

サブモジュールが更新されている間に、どういうわけかあなたがローカルサブモジュールディレクトリにローカルの変更を行っているため、これはまだうまくいかないことがあります。

ほとんどの場合、ローカルの変更はあなたがコミットしたいものではないかもしれません。サブモジュールなどでファイルが削除されたことが原因で発生する可能性があります。その場合は、ローカルサブモジュールディレクトリおよびプロジェクトの親ディレクトリでリセットを再実行します。

git submodule update --init --recursive 
107
pinux

あなたのメインプロジェクトは、サブモジュールがあるべき特定のコミットを指しています。 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がサブモジュールを更新します。

70
Mark Longair

この議論では、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
17
git pull --recurse-submodules

これは最新のコミットをすべて引っ張ります。

4

@Jasonはある意味で正しいですが、完全ではありません。

更新

登録されているサブモジュールを更新します。つまり、見つからないサブモジュールのクローンを作成し、それを含むリポジトリのインデックスで指定されたコミットをチェックアウトします。 --rebaseまたは--mergeが指定されていないか、キーサブモジュール$ name.updateがrebaseまたはmergeに設定されていない限り、これによってサブモジュールHEADが切り離されます。

それで、gitサブモジュールのアップデートはチェックアウトをします、しかし、事はそれが含まれているリポジトリのインデックスでコミットすることです。上流の新しいコミットをまだ知りません。それであなたのサブモジュールに行き、あなたが望むコミットを得てそしてメインレポジトリの中で更新されたサブモジュールの状態をコミットしそしてそれからgit submodule updateを実行してください

3
manojlds

私の場合は、gitを最新のものに更新し、同時に不足しているファイルを再投入したいと思いました。

以下は不足しているファイルを復元しました(ここで言及されていないようです--forceのおかげで)、しかしそれはどんな新しいコミットも引き寄せませんでした:

git submodule update --init --recursive --force

これはしました:

git submodule update --recursive --remote --merge --force

2
noseratio

あなたがホストブランチを知らないなら、これを作ります:

git submodule foreach git pull Origin $(git rev-parse --abbrev-ref HEAD)

それはmain gitの枝を得て、それからそれぞれのサブモジュールに対して同じ枝を引っ張ります。

1
NickUnuchek

これは、マスター上のすべてを最新のものに更新するための素晴らしいワンライナーです。

git submodule foreach 'git fetch Origin --tags; git checkout master; git pull' && git pull && git submodule update --init --recursive

Mark Jaquithに感謝

1
dustinrwh

最新のサブモジュールコミットの更新形式は次のようになります。

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

もう本当に静かではありません。
fc1b924submodule:port submoduleサブコマンド '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つのように見えても、オプションと見なすべきではありません。

0
VonC