programing

Git 하위 모듈을 오리진의 최신 커밋으로 업데이트

nasanasas 2020. 9. 29. 07:52
반응형

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 modA가 가져 할 나타나는, (그러나 수 없습니다 아마도,이 암호를 묻지 아니니까!)하지만, git loggit show새로운 커밋의 존재를 부정한다. 지금까지 rm모듈을-하고 다시 추가했지만 이것은 원칙적으로 잘못되었고 실제로는 지루합니다.


git submodule update명령은 실제로 슈퍼 프로젝트의 색인에 이미 지정된 커밋을 각 체크 아웃하기 위해 하위 모듈을 원한다고 Git에 알립니다. 원격에서 사용할 수있는 최신 커밋으로 하위 모듈 업데이트 하려면 하위 모듈에서 직접 수행해야합니다.

요약하면 다음과 같습니다.

# 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

각 하위 모듈의 업스트림에서 최신 변경 사항을 가져 와서 병합하고 하위 모듈의 최신 개정판을 확인합니다. 으로 문서의 풋 그것은 :

--먼

이 옵션은 업데이트 명령에만 유효합니다. 슈퍼 프로젝트의 기록 된 SHA-1을 사용하여 서브 모듈을 업데이트하는 대신 서브 모듈의 원격 추적 분기 상태를 사용하십시오.

이는 git pull일반적으로 정확히 원하는대로 각 하위 모듈에서 실행하는 것과 동일합니다 .


프로젝트 상위 디렉터리에서 다음을 실행합니다.

git submodule update --init

또는 재귀 하위 모듈이 실행되는 경우 :

git submodule update --init --recursive

하위 모듈이 업데이트되는 동안 로컬 하위 모듈 디렉토리에 로컬 변경 사항이 있기 때문에 때때로 이것은 여전히 ​​작동하지 않습니다.

대부분의 경우 로컬 변경은 커밋하려는 것이 아닐 수 있습니다. 하위 모듈의 파일 삭제 등으로 인해 발생할 수 있습니다. 그렇다면 로컬 하위 모듈 디렉터리와 프로젝트 상위 디렉터리에서 재설정을 수행하고 다시 실행합니다.

git submodule update --init --recursive

메인 프로젝트는 서브 모듈이 있어야하는 특정 커밋을 가리 킵니다. git submodule update초기화 된 각 하위 모듈에서 해당 커밋을 확인하려고합니다. 하위 모듈은 실제로 독립적 인 저장소입니다. 하위 모듈에 새 커밋을 만들고 푸시하는 것만으로는 충분하지 않습니다. 또한 주 프로젝트에서 새 버전의 하위 모듈을 명시 적으로 추가해야합니다.

따라서 귀하의 경우에는 하위 모듈에서 올바른 커밋을 찾아야합니다 master. 다음 의 팁이라고 가정하겠습니다 .

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를 업데이트하면 초기화되었다고 가정하고 하위 모듈을 업데이트합니다.


이 토론에서는 두 가지 다른 시나리오가 함께 혼합 된 것 같습니다.

시나리오 1

부모 저장소의 하위 모듈에 대한 포인터를 사용하여 부모 저장소가 가리키는 각 하위 모듈의 커밋을 확인하고 싶습니다. 모든 하위 모듈을 처음 반복하고 원격에서 업데이트 / 가져온 후에 가능합니다.

이것은 지적했듯이

git submodule foreach git pull origin BRANCH
git submodule update

OP가 목표로하는 시나리오 2

하나 이상의 하위 모듈에서 새로운 일이 발생했으며 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 개의 경로를 하드 코딩해야하기 때문입니다.

It would be cool to have an automated iteration through each submodule, updating the parent repository pointer (using git add) to point to the head of the submodule(s).

For this, I made this small Bash script:

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

To run it, execute

git-update-submodules.sh /path/to/base/repo BRANCH_NAME

Elaboration

First of all, I assume that the branch with name $BRANCH (second argument) exists in all repositories. Feel free to make this even more complex.

The first couple of sections is some checking that the arguments are there. Then I pull the parent repository's latest stuff (I prefer to use --ff (fast-forwarding) whenever I'm just doing pulls. I have rebase off, BTW).

git checkout $BRANCH && git pull --ff origin $BRANCH

Then some submodule initializing, might be necessary, if new submodules have been added or are not initialized yet:

git submodule sync
git submodule init
git submodule update

Then I update/pull all submodules:

git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"

Notice a few things: First of all, I'm chaining some Git commands using && - meaning previous command must execute without error.

After a possible successful pull (if new stuff was found on the remote), I do a push to ensure that a possible merge-commit is not left behind on the client. Again, it only happens if a pull actually brought in new stuff.

Finally, the final || true is ensuring that script continues on errors. To make this work, everything in the iteration must be wrapped in the double-quotes and the Git commands are wrapped in parentheses (operator precedence).

My favourite part:

for i in $(git submodule foreach --quiet 'echo $path')
do
  echo "Adding $i to root repo"
  git add "$i"
done

Iterate all submodules - with --quiet, which removes the 'Entering MODULE_PATH' output. Using 'echo $path' (must be in single-quotes), the path to the submodule gets written to output.

This list of relative submodule paths is captured in an array ($(...)) - finally iterate this and do git add $i to update the parent repository.

Finally, a commit with some message explaining that the parent repository was updated. This commit will be ignored by default, if nothing was done. Push this to origin, and you're done.

I have a script running this in a Jenkins job that chains to a scheduled automated deployment afterwards, and it works like a charm.

I hope this will be of help to someone.


Plain and simple, to fetch the submodules:

git submodule update --init --recursive

And now proceed updating them to the latest master branch (for example):

git submodule foreach git pull origin master

Note, while the modern form of updating submodule commits would be:

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

The older form was:

git submodule foreach --quiet git pull --quiet origin

Except... this second form is not really "quiet".

See commit a282f5a (12 Apr 2019) by Nguyễn Thái Ngọc Duy (pclouds).
(Merged by Junio C Hamano -- gitster -- in commit f1c9f6c, 25 Apr 2019)

submodule foreach: fix "<command> --quiet" not being respected

Robin reported that

git submodule foreach --quiet git pull --quiet origin

is not really quiet anymore.
It should be quiet before fc1b924 (submodule: port submodule subcommand 'foreach' from shell to C, 2018-05-10, Git v2.19.0-rc0) because parseopt can't accidentally eat options then.

"git pull" behaves as if --quiet is not given.

This happens because parseopt in submodule--helper will try to parse both --quiet options as if they are foreach's options, not git-pull's.
The parsed options are removed from the command line. So when we do pull later, we execute just this

git pull origin

When calling submodule helper, adding "--" in front of "git pull" will stop parseopt for parsing options that do not really belong to submodule--helper foreach.

PARSE_OPT_KEEP_UNKNOWN is removed as a safety measure. parseopt should never see unknown options or something has gone wrong. There are also a couple usage string update while I'm looking at them.

While at it, I also add "--" to other subcommands that pass "$@" to submodule--helper. "$@" in these cases are paths and less likely to be --something-like-this.
But the point still stands, git-submodule has parsed and classified what are options, what are paths.
submodule--helper should never consider paths passed by git-submodule to be options even if they look like one.


And Git 2.23 (Q3 2019) fixes another issue: "git submodule foreach" did not protect command line options passed to the command to be run in each submodule correctly, when the "--recursive" option was in use.

See commit 30db18b (24 Jun 2019) by Morian Sonnet (momoson).
(Merged by Junio C Hamano -- gitster -- in commit 968eecb, 09 Jul 2019)

submodule foreach: fix recursion of options

Calling:

git submodule foreach --recursive <subcommand> --<option>

leads to an error stating that the option --<option> is unknown to submodule--helper.
That is of course only, when <option> is not a valid option for git submodule foreach.

The reason for this is, that above call is internally translated into a call to submodule--helper:

git submodule--helper foreach --recursive \
    -- <subcommand> --<option>

This call starts by executing the subcommand with its option inside the first level submodule and continues by calling the next iteration of the submodule foreach call

git --super-prefix <submodulepath> submodule--helper \
   foreach --recursive <subcommand> --<option>

inside the first level submodule. Note that the double dash in front of the subcommand is missing.

This problem starts to arise only recently, as the PARSE_OPT_KEEP_UNKNOWN flag for the argument parsing of git submodule foreach was removed in commit a282f5a.
Hence, the unknown option is complained about now, as the argument parsing is not properly ended by the double dash.

This commit fixes the problem by adding the double dash in front of the subcommand during the recursion.


git pull --recurse-submodules

This will pull all the latest commits.


In my case, I wanted git to update to the latest and at the same time re-populate any missing files.

The following restored the missing files (thanks to --force which doesn't seem to have been mentioned here), but it didn't pull any new commits:

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

This did:

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


@Jason is correct in a way but not entirely.

update

Update the registered submodules, i.e. clone missing submodules and checkout the commit specified in the index of the containing repository. This will make the submodules HEAD be detached unless --rebase or --merge is specified or the key submodule.$name.update is set to rebase or merge.

So, git submodule update does checkout, but it is to the commit in the index of the containing repository. It does not yet know of the new commit upstream at all. So go to your submodule, get the commit you want and commit the updated submodule state in the main repository and then do the git submodule update.


Here's an awesome one-liner to update everything to the latest on master:

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

Thanks to Mark Jaquith


If you don't know the host branch, make this:

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

It will get a branch of the main Git repository and then for each submodule will make a pull of the same branch.

참고URL : https://stackoverflow.com/questions/5828324/update-git-submodule-to-latest-commit-on-origin

반응형