원래 Git 서브 모듈을 최신 커밋으로 업데이트


853

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모듈을 다듬고 다시 추가했지만, 이것은 원칙적으로 잘못되고 실제로 지루합니다.


5
David Z의 대답은이 작업을 수행하는 더 좋은 방법처럼 보입니다. 이제 Git에 --remote옵션 을 통해 필요한 기능이 내장되어 있으므로 Jason의 답변에서 "손으로"접근하는 대신 승인 된 답변으로 표시하는 것이 좋을까요?
Mark Amery

1
@MarkAmery에 매우 동의합니다. Jason이 작동하는 솔루션을 제공했지만 하위 모듈의 커밋 포인터를 잘못된 커밋 식별자에 남겨두기 때문에 의도 한 방법이 아닙니다. --remote이 시점에서 새로운 것이 확실히 더 나은 솔루션이며,이 질문은 Github Gist와 하위 모듈에 관한 것이므로 들어오는 독자가 새로운 답변을 보는 것이 더 나을 것이라고 생각합니다.
MutantOctopus

좋은 터치 hunter2암호 : O)
lfarroco

답변:


1458

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

335
git submodule foreach git pull
Mathias Bynens

87
@Nicklas이 경우을 사용하십시오 git submodule foreach git pull origin master.
Mathias Bynens

54
이 시점에서 수정 사항에 대한 모든 수정 사항과 함께 설명 블로그 게시물을 작성하고 저를 알려줄 사람이 필요합니다. 부디.
Suz

25
'foreach'접근 방식의 사소한 개선-하위 모듈 내에 하위 모듈이있는 경우 재귀를 추가 할 수 있습니다. 그래서 : git submodule foreach --recursive git pull origin master.
오리온 엘렌 질

4
@Abdull -a에 대한 스위치 git commit"수정 및 삭제 된 자동으로 무대 파일에 명령을 [S]에게,하지만 당신이 망할 놈의 말하지 않은 새 파일에 대한 영향을받지 않습니다."
godfrzero

473

Git 1.8.2에는 새로운 --remote동작 인이 기능이 있습니다. 달리는

git submodule update --remote --merge

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

--먼

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

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


4
" git pull각 서브 모듈에서 실행하는 것과 동일 함 " 명확히하기 위해, 사용자의 관점과 대답 사이에 차이가 없습니다 git submodule foreach git pull.
Dennis

3
@ Dennis 그것은 본질적으로 같은 일을하지만 기능이 정확히 같은지 확실하지 않습니다 . 두 가지 명령이 일부 구성 설정에 응답하는 방식과 같이 내가 모르는 사소한 차이가있을 수 있습니다.
David Z

5
이 10,000X를 공표 할 수 있기를 바랍니다. 왜 이것이 git의 문서에 표시되지 않습니까? 엄청난 감독.
serraosays

4
나를 위해 그들은 실제로 상당히 크게 달랐다. foreach git pull그것들을 체크 아웃했지만 메인 리포지토리의 포인터를 업데이트하여 하위 모듈의 새로운 커밋을 가리 키지 않았습니다. --remote그것으로 만 최신 커밋을 가리 켰습니다.
Ela782

5
왜 --merge 옵션인가? 어떤 차이가 있습니까?
mFeinstein

127

프로젝트 상위 디렉토리에서 다음을 실행하십시오.

git submodule update --init

또는 재귀 하위 모듈이있는 경우 다음을 실행하십시오.

git submodule update --init --recursive

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

대부분의 경우 로컬 변경이 커밋하려는 것이 아닐 수도 있습니다. 하위 모듈 등에서 파일이 삭제되어 발생할 수 있습니다. 그렇다면 로컬 하위 모듈 디렉토리와 프로젝트 상위 디렉토리에서 재설정하십시오.

git submodule update --init --recursive

5
이것이 정답입니다. 어떻게 든 원격 저장소로 밀어 넣을 수 있습니까?
MonsterMMORPG

이것은 새로운 서브 모듈에서 작동합니다! 다른 모든 것을 업데이트 할 수는 있지만이 명령을 실행할 때까지 새 하위 모듈의 폴더는 비어 있습니다.
Alexis Wilke 3

1
기존 서브 모듈에 대한 변경 사항을 가져 오지 않습니다
Sergey G.

73

기본 프로젝트는 서브 모듈이 있어야하는 특정 커밋을 가리 킵니다. 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를 업데이트하면 하위 모듈이 초기화되었다고 가정하여 하위 모듈을 업데이트합니다.


24

이 토론에서 두 가지 시나리오가 혼합되어있는 것 같습니다.

시나리오 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 하위 모듈에 대한 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 (두 번째 인수) 인 브랜치가 모든 리포지토리에 있다고 가정합니다. 이것을 훨씬 더 복잡하게 만드십시오.

첫 번째 섹션은 인수가 있는지 확인하는 것입니다. 그런 다음 부모 저장소의 최신 항목을 가져옵니다 (풀을 할 때마다 --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 명령을 사용하여 연결 &&합니다. 즉, 이전 명령은 오류없이 실행되어야합니다.

가능한 성공적인 끌어 오기 (원격에서 새 항목을 찾은 경우) 후 가능한 병합 커밋이 클라이언트에 남아 있지 않도록 확인합니다. 다시 말하지만, 잡아 당기는 것이 실제로 새로운 물건을 가져온 경우 에만 발생 합니다 .

마지막으로 || true스크립트는 오류가 계속 발생하도록합니다. 이 작업을 수행하려면 반복의 모든 항목을 큰 따옴표로 묶어야하고 Git 명령은 괄호로 묶어야합니다 (연산자 우선 순위).

내가 가장 좋아하는 부분 :

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

모든 하위 모듈을 반복합니다. with --quiet는 'Entering MODULE_PATH'출력을 제거합니다. 사용 'echo $path'(작은 따옴표에 있어야합니다), 서브 모듈의 경로는 출력에 기록됩니다.

이 상대 하위 모듈 경로 목록은 배열 ( $(...))로 캡처됩니다. 마지막으로이를 반복 git add $i하고 상위 리포지토리를 업데이트합니다.

마지막으로, 부모 저장소가 업데이트되었음을 ​​설명하는 메시지가있는 커밋. 아무 것도 수행하지 않으면이 커밋은 기본적으로 무시됩니다. 이것을 원점으로 밀면 완료됩니다.

Jenkins 작업 에서이 스크립트를 실행하여 나중에 예약 된 자동 배포에 연결하며 매력처럼 작동합니다.

이것이 누군가에게 도움이되기를 바랍니다.


2
! @ # $ % SO 우리는 당신과 비슷한 스크립트를 사용하고 있습니다; 한 가지 참고 사항 :```foreach --quiet 'echo $ path'```대신 git submodule foreach --recursive --quiet pwd```를 for 루프 안에 사용합니다. 이 pwd명령은 존재하는 각 하위 모듈에 대해 적절한 '절대 경로'를 인쇄합니다. 대규모 프로젝트에있을 수있는 하위 모듈 내 하위 모듈을 포함하여 모든 하위 모듈 --recursive을 방문하도록합니다 . 두 가지 방법 모두 공백을 포함하는 디렉토리에 문제를 일으 킵니다. 예를 들어 정책은 프로젝트의 어느 곳에서도 공백을 사용 하지 않아야 합니다. /c/Users/Ger/Project\ Files/...
Ger Hobbelt

2
이것은 좋으며 질문의 내용에 대한 오해가 있음이 맞습니다. 그러나 David Z의 탁월한 답변에서 지적했듯이 2013 년 중반 이후 Git에 기능이 내장되어 있으므로 스크립트가 필요하지 않습니다. 그들은 --remote옵션 을 추가했습니다 . git submodule update --remote대략 스크립트가하는 방식으로 작동합니다.
Mark Amery

@GerHobbelt 감사합니다. 당신은 옳습니다, 우리는 단지 1 레벨의 서브 모듈을 가지고 있기 때문에 재귀 적으로 생각하지 않았습니다. 스크립트가 예상대로 작동하는지 확인할 수 있기 전에 스크립트를 업데이트하지 않지만 분명히 내 스크립트는 하위 하위 모듈을 무시합니다. 폴더의 공백과 관련하여 이것은 피해야 할 것 같습니다. : S
Frederik Struck-Schøning

@MarkAmery 의견을 보내 주셔서 감사합니다. 그러나 하나의 문제가 있습니다 : 인수로 하위 모듈에 대한 분기를 지정할 수는 없습니다. git manual에서 : The remote branch used defaults to master, but the branch name may be overridden by setting the submodule.<name>.branch option in either .gitmodules or .git/config (with .git/config taking precedence).master 이외의 다른 지점 으로이 작업을 수행 할 때마다 .gitmodules 또는 .git / config를 편집하고 싶지 않습니다. 그러나 어쩌면 내가 뭔가를 놓친 것입니까? 또한이 방법은 재귀 병합을 시행하는 것으로 보입니다 (따라서 빨리 감기의 가능성이 빠져 있음).
Frederik Struck-Schøning

마지막으로 : @DavidZ의 방법을 시도했지만, 정확한 일을하지 않는 것 같습니다. (그리고 어떤 op가 요청했는지) : 하위 모듈의 HEAD 커밋을 부모에게 추가 (예 : "포인터 업데이트") ). 그러나 모든 하위 모듈에서 최신 변경 사항을 가져오고 병합하는 데있어 단독 작업을 매우 잘 수행하는 것처럼 보입니다. 아아, 기본적으로 마스터 브랜치에서만 .gitmodules 파일을 편집하지 않는 한 (위 참조).
Frederik Struck-Schøning

19

하위 모듈을 가져 오는 간단하고 간단합니다.

git submodule update --init --recursive

이제 최신 마스터 지점으로 업데이트를 진행하십시오 (예 :).

git submodule foreach git pull origin master

12

하위 모듈 커밋을 업데이트하는 최신 형식은 다음과 같습니다.

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

이전 형식은 다음과 같습니다.

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

빼고 ...이 두 번째 형태는 실제로 "조용하지 않다".

Nguyễn Thái Ngọc Duy ( )의 커밋 a282f5a (2019 년 4 월 12 일)를 참조하십시오 . (의해 병합 Junio C 하마노 - -커밋 f1c9f6c 25 사월 2019)pclouds
gitster

submodule foreach: 수정 <command> --quiet되지 않은 " " 수정

로빈은

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

더 이상 조용하지 않습니다. 실수로 옵션을 먹을 수 없으므로 fc1b924 ( : 쉘에서 C로 포트 하위 명령 ' ', 2018-05-10, Git v2.19.0-rc0)
보다 조용해야합니다 .submodulesubmoduleforeachparseopt

" git pull" --quiet가 제공되지 않은 것처럼 동작 합니다.

이것은 parseoptin submodule--helper--quiet아닌 foreach의 옵션 인 것처럼 두 옵션을 모두 구문 분석하려고하기 때문에 발생합니다 git-pull.
구문 분석 된 옵션이 명령 행에서 제거됩니다. 나중에 당길 때, 우리는 이것을 실행합니다

git pull origin

하위 모듈 헬퍼를 호출 할 때 " --"앞에 " "를 추가하면 실제로 속하지 않는 옵션 구문 분석 git pull이 중지 parseopt됩니다 submodule--helper foreach.

PARSE_OPT_KEEP_UNKNOWN안전 조치로 제거됩니다. parseopt알 수없는 옵션이나 무언가 잘못되었음을 보지 않아야합니다. 내가 보면서 몇 가지 사용법 문자열 업데이트가 있습니다.

그 동안 " --"을 전달하는 다른 하위 명령 에도 " "을 추가 $@합니다 submodule--helper. " $@"이 경우 경로가 될 가능성이 적습니다 --something-like-this.
그러나 요점은 여전히 ​​선택적이며 git-submodule경로이며 무엇인지 파싱하고 분류했습니다.
submodule--helper경로가 경로 git-submodule처럼 보이지만 전달 된 경로 를 옵션으로 간주해서는 안됩니다 .


그리고 Git 2.23 (Q3 2019)은 또 다른 문제를 해결합니다. git submodule foreach" --recursive"옵션이 사용 중일 때 " " 명령에 전달 된 명령 행 옵션이 각 서브 모듈에서 올바르게 실행되도록 보호하지 않았습니다 .

Morian Sonnet ( momoson)의 commit 30db18b (2019 년 6 월 24 일)를 참조하십시오 .
( Junio ​​C gitsterHamano 에 의해 합병 -- 커밋 968eecb , 2019 년 7 월 9 일)

submodule foreach: 옵션 재귀 수정

부름:

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

옵션 --<option>을 알 수 없다는 오류가 발생 합니다 submodule--helper.
물론에 <option>대한 유효한 옵션이 아닌 경우에만 해당됩니다 git submodule foreach.

그 이유는 위의 호출이 내부적으로 하위 모듈에 대한 호출로 변환되기 때문입니다.

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

이 호출은 첫 번째 레벨 서브 모듈 내부의 옵션을 사용하여 하위 명령을 실행하여 시작하고 다음 반복 호출하여 계속 submodule foreach전화를

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

첫 번째 레벨 하위 모듈 내부. 부속 명령 앞의 이중 대시가 누락되었습니다.

이 문제는 커밋 a282f5a 에서 PARSE_OPT_KEEP_UNKNOWN인수 구문 분석을위한 플래그 git submodule foreach가 제거 되었기 때문에 최근에 발생하기 시작했습니다 . 따라서 인수 파싱이 이중 대시로 올바르게 끝나지 않으므로 알 수없는 옵션이 현재 불평됩니다.

이 커밋은 재귀 중에 하위 명령 앞에 이중 대시를 추가하여 문제를 해결합니다.


7
git pull --recurse-submodules

이것은 모든 최신 커밋을 가져옵니다.


4

필자의 경우 git최신으로 업데이트하고 누락 된 파일을 다시 채우고 싶었 습니다.

다음은 누락 된 파일을 복원 --force했지만 (여기에 언급되지 않은 것으로 보입니다) 새로운 커밋을 가져 오지 않았습니다.

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

이것은했다 :

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


3

@Jason은 올바른 방식이지만 완전히는 아닙니다.

최신 정보

등록 된 서브 모듈, 즉 누락 된 서브 모듈을 복제하고 포함 저장소의 색인에 지정된 커밋을 체크 아웃하십시오. --rebase 또는 --merge가 지정되거나 키 submodule. $ name.update가 리베이스 또는 병합으로 설정되지 않은 경우 서브 모듈 HEAD가 분리됩니다.

따라서 git submodule update체크 아웃하지만 포함 리포지토리의 인덱스에서 커밋됩니다. 아직 새로운 커밋 업스트림을 전혀 알지 못합니다. 따라서 서브 모듈로 이동하여 원하는 커밋을 가져 와서 메인 리포지토리에서 업데이트 된 서브 모듈 상태를 커밋 한 다음을 수행하십시오 git submodule update.


1
하위 모듈을 다른 커밋으로 git submodule update이동 한 다음 run을 수행 하면 update가 하위 모듈을 수퍼 프로젝트의 현재 HEAD에 지정된 커밋으로 이동합니다. (슈퍼 프로젝트에서 가장 최근의 커밋이 무엇이든 하위 프로젝트가 있어야한다고 말합니다. Jason의 게시물에서 설명 한 후이 동작은 논리적입니다.) 하위 프로젝트가 잘못된 커밋에있는 경우에만 가져 오는 것처럼 보입니다. , 그것은 내 혼란에 추가되었습니다.
Thanatos

2

다음은 마스터의 모든 것을 최신으로 업데이트하는 멋진 원 라이너입니다.

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

Mark Jaquith에게 감사합니다


2

호스트 분기를 모르는 경우 다음을 수행하십시오.

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

메인 Git 리포지토리의 브랜치를 가져오고 각 서브 모듈마다 동일한 브랜치를 가져옵니다.


0

master각 하위 모듈에 대해 분기 를 체크 아웃하려는 경우 해당 용도로 다음 명령을 사용할 수 있습니다.

git submodule foreach git checkout master
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.