힘내 서브 모듈 헤드 '참조는 나무가 아닙니다'오류


305

잘못된 커밋을 가리키는 서브 모듈이있는 프로젝트가 있습니다. 서브 모듈 커밋은 로컬로 유지되었으며 다른 리포지토리에서 가져 오려고하면 다음과 같은 결과가 나타납니다.

$ git submodule update
fatal: reference is not a tree: 2d7cfbd09fc96c04c4c41148d44ed7778add6b43
Unable to checkout '2d7cfbd09fc96c04c4c41148d44ed7778add6b43' in submodule path 'mysubmodule'

내가 로컬로 변경할 수있는 방법은,이 서브 모듈의 HEAD가의 repo에서 누르지 않고해야합니다 알고 않습니다 저지했다 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

내가 분명하고 있는지 확실하지 않습니다 ... 여기 내가 찾은 비슷한 상황이 있습니다.


11
하위 모듈과 관련하여 "치명적 : 참조는 트리가 아닙니다"는 일반적으로 상위 리포지토리가 아직 푸시되지 않았거나 다른 방식으로 조여 졌을 것으로 예상되는 하위 모듈 커밋을 의미하는 것으로 보입니다. 우리에게이 혼란스러운 오류 메시지는 누군가가 밀어내는 것을 잊어 버린 서브 모듈을 밀어서 해결되었습니다.
Chris Moschini

1
@ChrisMoschini-방금 그 문제가 있었고 그것이 내 "솔루션"이었고 메인 리포지토리를 밀고 당겼지만 마지막 커밋을 서브 모듈의 리포지토리로 푸시하는 것을 잊었습니다. 감사!
Rotem

어쩌면 당신은 최신 서브 모듈 커밋을 추진하는 것을 잊었다
Hafenkranich

답변:


378

서브 모듈의 리포지토리에 사용하려는 커밋이 포함되어 있다고 가정하면 (수퍼 프로젝트의 현재 상태에서 참조되는 커밋과 달리) 두 가지 방법이 있습니다.

첫 번째는 사용하려는 서브 모듈의 커밋을 이미 알고 있어야합니다. 하위 모듈을 직접 조정 한 다음 수퍼 프로젝트를 업데이트하여 "내부, 외부"에서 작동합니다. 두 번째는“외부에서”서브 모듈을 수정 한 수퍼 프로젝트의 커밋을 찾은 다음 다른 서브 모듈 커밋을 참조하도록 수퍼 프로젝트의 인덱스를 재설정하여 작동합니다.

뒤집어서

당신이 이미 알고있는 경우에는 사용에 서브 모듈, 원하는 커밋 된 cd다음, 당신이 원하는 커밋 체크 아웃, 서브 모듈로를 git add하고 git commit는 다시 슈퍼 프로젝트이다.

예:

$ git submodule update
fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556
Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub'

하위 모듈에서 게시되지 않은 커밋을 나타내는 수퍼 프로젝트 커밋을 만들었습니다 sub. 어쨌든 우리는 이미 서브 모듈이 커밋되기를 원한다는 것을 알고 있습니다 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. 거기 가서 직접 확인하십시오.

서브 모듈에서 체크 아웃

$ cd sub
$ git checkout 5d5a3ee314476701a20f2c6ec4a53f88d651df6c
Note: moving to '5d5a3ee314476701a20f2c6ec4a53f88d651df6c' which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
  git checkout -b <new_branch_name>
HEAD is now at 5d5a3ee... quux
$ cd ..

커밋을 체크 아웃하기 때문에 서브 모듈에서 HEAD가 분리됩니다. 서브 모듈이 브랜치를 사용하고 있는지 확인 git checkout -b newbranch <commit>하려면 커밋에서 브랜치를 생성 및 체크 아웃하거나 원하는 브랜치를 체크 아웃하십시오 (예 : 원하는 커밋이있는 브랜치).

슈퍼 프로젝트 업데이트

하위 모듈의 체크 아웃은 작업 트리 변경으로 수퍼 프로젝트에 반영됩니다. 따라서 우리는 수퍼 프로젝트의 색인 변경을 준비하고 결과를 검증해야합니다.

$ git add sub

결과 확인

$ git submodule update
$ git diff
$ git diff --cached
diff --git c/sub i/sub
index e47c0a1..5d5a3ee 160000
--- c/sub
+++ i/sub
@@ -1 +1 @@
-Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

서브 모듈이 이미 지정된 커밋에 있으므로 서브 모듈 업데이트가 자동입니다. 첫 번째 diff는 인덱스와 작업 트리가 동일 함을 보여줍니다. 세 번째 차이점은 단계적 변경 만이 sub서브 모듈을 다른 커밋으로 옮기는 것임을 보여줍니다 .

범하다

git commit

이것은 고정 서브 모듈 엔트리를 커밋한다.


밖에서

서브 모듈에서 어떤 커밋을 사용해야하는지 확실하지 않은 경우 수퍼 프로젝트의 히스토리를보고 안내 할 수 있습니다. 수퍼 프로젝트에서 직접 재설정을 관리 할 수도 있습니다.

$ git submodule update
fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556
Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub'

위와 같은 상황입니다. 그러나 이번에는 서브 모듈에 담그지 않고 수퍼 프로젝트에서 수정하는 데 중점을 둘 것입니다.

슈퍼 프로젝트의 Errant Commit 찾기

$ git log --oneline -p -- sub
ce5d37c local change in sub
diff --git a/sub b/sub
index 5d5a3ee..e47c0a1 160000
--- a/sub
+++ b/sub
@@ -1 +1 @@
-Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c
+Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
bca4663 added sub
diff --git a/sub b/sub
new file mode 160000
index 0000000..5d5a3ee
--- /dev/null
+++ b/sub
@@ -0,0 +1 @@
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

OK,에서 잘못 된 것처럼 보이 ce5d37c므로 하위 모듈을 부모 ( ce5d37c~) 에서 복원합니다 .

또는 패치 텍스트 ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) 에서 서브 모듈의 커밋을 가져 와서 위의 "내부, 외부"프로세스를 대신 사용할 수 있습니다.

슈퍼 프로젝트에서 체크 아웃

$ git checkout ce5d37c~ -- sub

이렇게하면 서브 프로젝트 항목이 수퍼 프로젝트 sub에서 커밋 ce5d37c~된 항목으로 재설정 됩니다.

서브 모듈 업데이트

$ git submodule update
Submodule path 'sub': checked out '5d5a3ee314476701a20f2c6ec4a53f88d651df6c'

하위 모듈 업데이트가 정상적으로 진행되었습니다 (분리 된 HEAD를 나타냄).

결과 확인

$ git diff ce5d37c~ -- sub
$ git diff
$ git diff --cached
diff --git c/sub i/sub
index e47c0a1..5d5a3ee 160000
--- c/sub
+++ i/sub
@@ -1 +1 @@
-Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556
+Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c

첫 번째 차이점 sub은 현재와 동일 하다는 것을 보여줍니다 ce5d37c~. 두 번째 diff는 인덱스와 작업 트리가 동일 함을 보여줍니다. 세 번째 차이점은 단계적 변경 만이 sub서브 모듈을 다른 커밋으로 옮기는 것만 보여줍니다 .

범하다

git commit

이것은 고정 서브 모듈 엔트리를 커밋한다.


"Outside, In"접근 방식에서 "ce5d37c에서 문제가 발생한 것처럼 보이는 이유"를 설명 할 수 있습니까? 나쁜 일을 저지르는 손가락은 무엇입니까?
개렛 올브라이트

5
@Garrett : e47c0a에 대한 로컬 저장소에 존재하지 않지만 sub수퍼 프로젝트 sub가 해당 커밋을 가리키는 커밋입니다. 다른 사람 e47c0a이의 사본에서 생성 sub하고 해당 커밋을 가리 키도록 수퍼 프로젝트를 업데이트하고 e47c0a에 대한 중앙 / 공유 저장소로 푸시하지 않고 수퍼 프로젝트를 푸시 했기 때문에 이런 일이 발생했을 수 있습니다 sub. 우리가 중앙 / 공유 슈퍼 프로젝트에서 끌어 때 우리는 그 점을 커밋 얻을 sube47c0a커밋,하지만 우리는 "볼"수 없습니다. ce5d37cdiff를 기반으로하여 도입 되었기 때문에 의심 스럽다 e47c0a.
Chris Johnsen

sub하위 모듈로 보유한 상위 저장소에 보관 된 특정 해시가있는 위치 와 상위 sub의 이전 상태에 의존하지 않고 직접 현재 HEAD로 직접 조작 할 수 있는지 여부 는 여전히 모호 합니다. 항상 도움이되는 것은 아닙니다.
matanster


187

이 시도:

git submodule sync
git submodule update

2
안타깝게도 서브 모듈 중 하나는 add 명령을 사용하여 기본 자식 저장소의 대상이되었으므로 실행 취소하는 데 문제가 있습니다.
Daniel

9
나도 일했다. 그래도 이유를 알고 싶습니다.
BenBtg

12
git submodule sync주어진 서브 모듈에 대한 원격의 URL이 변경된 시나리오에서 수행 이 필요 하다는 것이 밝혀 졌습니다. 이 경우 공개 저장소에서 하위 모듈을 추가 한 다음 URL을 개인용 포크로 변경하고이 특정 피클에 들어갔습니다.
Samscam

예를 들어 : github repo (B)를 가리키는 하위 모듈로 repo (A)를 설정했습니다. 다른 사람의 github 저장소에서 B를 가리키고 싶기 때문에 repo A에 지점을 만들었습니다. 약간의 어려움을 겪고 지점을 커밋 한 후 내 repo A를 마스터로 다시 전환하고 repo B와 함께이 문제가 발생했습니다. @Lonre Wang의 솔루션으로 해결되었습니다.
fbicknel

2
Lonre Wang의 답변이 문제를 해결해야 할 사람이 아무도 없다고 가정하면 (Chris Johnsen의 훌륭한 답변이 필요한 경우), 문제를 해결해야합니다. 이 경우 문제가있는 하위 모듈이있는 하위 모듈로 cd하고 위의 명령을 실행해야합니다. 업데이트에는 --recursive 옵션 (git submodule update --recursive)이 있지만 sync는 그렇지 않습니다. 문제가있는 하위 모듈이있는 하위 모듈 내에서 'git submodule sync'를 수동으로 실행해야합니다. 이것은 내 문제였다;).
Carlo Wood

16

이 오류는 서브 모듈에서 커밋이 누락되었음을 의미 할 수 있습니다. 즉, 저장소 (A)는 서브 모듈 (B)을 갖는다. A는 B를로드하여 특정 커밋을 가리 킵니다 (B). 커밋이 누락 된 경우 해당 오류가 발생합니다. 가능한 원인 : 커밋에 대한 참조는 A로 푸시되었지만 실제 커밋은 B에서 푸시되지 않았습니다.

권한 문제가 있고 커밋을 가져올 수 없습니다 (git + ssh를 사용하는 경우 가능).

.git / config 및 .gitmodules에서 하위 모듈 경로가 제대로 표시되는지 확인하십시오.

마지막으로 시도해야 할 것-서브 모듈 디렉토리 내부 : git reset HEAD --hard


3
나는 이미 질문에서 설명했다. 질문 자체는 그것을 해결하는 방법이었다. 거의 2 년 전에 이미 성공적으로 답변을 받았습니다 ... 권한은 이와 관련이 없습니다.
Mauricio Scheffer

1
당신은 그것을 말했지만, 당신은 그것을 설명하지 않았습니다.
Daniel Tsadok

내 요점은,이 답변은 중요한 정보를 추가하지 않는다는 것입니다. 삭제하겠습니다.
Mauricio Scheffer

4
"git reset HEAD --hard"도 나에게 도움이되었다. 나는 이전 솔루션도 시도했지만 주사위는 없었습니다. 감사!
Virgil

1
각 스레드는 온라인으로 자신의 작은 세계입니다. 당신이하는 말은 당신이 원하는 것을 존중하는 맥락에서 사람들이 당신의 의견을 짜기 위해 당신의 개인 역사를 연구 할 것이라고 기대할 수 없습니다. 친절하고 정중하게 대하십시오. 사람들에게 당신의 개인적인 특성에 대해 이해하도록 요구할 필요는 없습니다. 외부인처럼 중립적 맥락에서 의견을 읽을 수 있다면 내 비판을 이해할 것입니다.
Stabledog

10

가능한 원인

다음과 같은 경우에 발생할 수 있습니다.

  1. 하위 모듈이 제자리에서 편집되었습니다
  2. 서브 모듈이 커밋되었습니다. 이 모듈은 지정된 서브 모듈의 해시를 업데이트합니다.
  3. 하위 모듈이 푸시되지 않았습니다 .

예를 들어 이와 같은 일이 발생했습니다.

$ cd submodule
$ emacs my_source_file  # edit some file(s)
$ git commit -am "Making some changes but will forget to push!"

이 시점에서 서브 모듈이 푸시되어야합니다.

$ cd .. # back to parent repository
$ git commit -am "updates to parent repository"
$ git push origin master

결과적으로 누락 된 커밋은 여전히 ​​로컬 디스크에 있기 때문에 원격 사용자가 찾을 수 없습니다.

해결책

Informa 하위 모듈을 밀어서 수정 한 사람, 즉

$ cd submodule
$ git push

6

내가 할 때이 오류가 발생했습니다.

$ git submodule update --init --depth 1

그러나 부모 프로젝트의 커밋은 이전 커밋을 가리 켰습니다.

하위 모듈 폴더를 삭제하고 실행 중 :

$ git submodule update --init

문제를 해결하지 못했습니다. 나는 repo를 삭제하고 깊이 플래그없이 다시 시도했으며 작동했습니다.

이 오류는 Ubuntu 16.04 git 2.7.4에서는 발생하지만 Ubuntu 18.04 git 2.17에서는 발생하지 않습니다. TODO는 정확한 고정 커밋 또는 버전을 찾습니다.


우리 팀은 코드에서 서브 모듈을 버려 너무 번거 롭습니다.
Plato

1
당신의 대안은 무엇입니까?
nuzzolilo

@nuzzolilo 우리 username/repo#sha가 package.json에 추가 한 훨씬 더 유연한 옵션은 도커 컨테이너 세트로 시스템을 구성하는 것입니다
Plato

3
너무 짜증나. --depth=1repo 기록이 필요하지 않을 때 너무 많은 대역폭을 절약합니다. 누군가 왜 이런 일이 일어나고 있는지 알거나 알고 있다면 알고 싶습니다.
i336_

@ i336_ 내가 여기에 문제를 완화하는 데 도움이 cmake 도우미 쓴 이유를 설명 할 수는 없지만 : github.com/LMMS/lmms/blob/...를 . deinit대부분의 시간에 문제를 해결 하는 접근 방식을 사용합니다 . 빌드 시스템과 번들로 제공되는 경우 최종 사용자는 빌드 시스템이 서브 모듈을 가져 오도록하고 깨진 recursive명령을 모두 버릴 수 있습니다. 서브 모듈이 강제 푸시를 수행하고 커밋을 완전히 지우는 등 여전히 이러한 상황이 발생합니다.
tresf

5

리베이스 된 리포지토리를 가리키는 하위 모듈이 있고 지정된 커밋이 "사라진"경우에도 발생할 수 있습니다. 커밋은 여전히 ​​원격 리포지토리에있을 수 있지만 브랜치에는 없습니다. 새로운 브랜치를 만들 수 없다면 (예 : 저장소가 아닌), 새로운 커밋을 가리 키도록 수퍼 프로젝트를 업데이트해야합니다. 또는 서브 모듈 사본 중 하나를 다른 곳으로 푸시 한 다음 대신 해당 저장소를 가리 키도록 수퍼 프로젝트를 업데이트 할 수 있습니다.


5

지점이 최신 상태가 아닌 간단한 해결책 일 수 있습니다. git fetch


2

이 답변은 터미널 git 환경이 제한된 SourceTree 사용자를위한 것입니다.

Git 프로젝트 (슈퍼 프로젝트)에서 문제가있는 하위 모듈을 엽니 다.

가져 오기 및 '모든 태그 가져 오기'가 선택되어 있는지 확인하십시오.

Git 프로젝트를 리베이스하십시오.

이것은 '참조는 나무가 아니다'문제를 10 번 중 9 번 해결한다. 1 번은 그렇지 않습니다. 최고의 답변으로 설명 된 터미널 수정입니다.


1

하위 모듈 내역은 하위 모듈 git에 안전하게 유지됩니다.

그렇다면 왜 서브 모듈을 삭제하고 다시 추가하지 않겠습니까?

그렇지 않으면, 당신은 수동으로 편집하려고했던 HEAD또는를 refs/master/head서브 모듈 내에서.git


1
이하지 않습니다 작업 때문에 이 다른 곳에서 지역의 repo에 아니라 2d7cfbd09fc96c04c4c41148d44ed7778add6b43에 대한 참조입니다, 하지만 출판
마우 페르

1

확실하게 git바이너리를 업데이트하십시오 .

Windows 용 GitHub git version 1.8.4.msysgit.0에는 문제 가있는 버전 이 있습니다. 업데이트하면 해결되었습니다.


1

내 경우에는 위의 답변 중 어느 것도 좋은 답변이라고해도 문제를 해결하지 못합니다. 따라서 솔루션을 게시합니다 (제 경우에는 클라이언트 A와 B의 두 가지 git 클라이언트가 있습니다).

  1. 하위 모듈의 디렉토리로 이동하십시오.

    cd sub
    
  2. 마스터 체크 아웃 :

    git checkout master
    
  3. 두 클라이언트 모두 볼 수있는 커밋 코드로 리베이스

  4. 부모의 디렉토리로 돌아갑니다.

  5. 마스터하다

  6. 다른 클라이언트로 변경하고 rebase다시 수행 하십시오.

  7. 마침내 이제는 잘 작동합니다! 어쩌면 몇 가지 커밋을 잃을 수도 있지만 작동합니다.

  8. 참고로, 서브 모듈을 제거하려고 시도하지 마십시오. 서브 모듈은 .git/modules로컬에 반응하지 않으면 서브 모듈을 다시 읽을 수 없습니다.


1

git repo를 서브 모듈의 헤드와 동기화하기 위해 실제로 원하는 경우 서브 모듈을 제거한 다음 읽는 것이 히스토리와 땜질을 피한다는 것을 알았습니다. 불행히도 서브 모듈을 제거하려면 단일 git 명령이 아닌 해킹이 필요하지만 가능합니다.

https://gist.github.com/kyleturner/1563153 에서 영감을 얻은 하위 모듈을 제거하기 위해 수행 한 단계 :

  1. git rm --cached를 실행하십시오.
  2. .gitmodules 파일에서 관련 행을 삭제하십시오.
  3. .git / config에서 관련 섹션을 삭제하십시오.
  4. 이제 추적되지 않은 서브 모듈 파일을 삭제하십시오.
  5. .git / modules / 디렉토리를 제거하십시오

다시 말하지만, 서브 모듈의 헤드를 다시 가리키고 서브 모듈의 로컬 사본을 그대로 유지해야하므로 복잡하지 않은 경우 유용 할 수 있습니다. 소스 모듈의 출처가 어디에 있든지 서브 모듈 "오른쪽"을 자체 리포지토리로 가지고 있다고 가정하고 서브 모듈로 포함시키기 만하면됩니다.

참고 : 간단한 커밋이나 푸시 이외의 조작 또는 git 명령을 수행하기 전에 항상 프로젝트의 전체 사본을 만드십시오. 나는 다른 모든 답변과 일반적인 git 지침으로 조언 할 것입니다.


1

이 문제에 대해 막 넘어서서 이러한 해결책 중 어느 것도 나를 위해 일하지 않았습니다. 내 문제에 대한 해결책으로 밝혀진 것은 실제로 훨씬 간단합니다 : 업그레이드 Git. 광산은 1.7.1 였고 2.16.1 (최신)로 업그레이드 한 후 문제는 흔적없이 사라졌습니다! 내가 여기에 떠날 것 같아, 누군가를 돕기를 바랍니다.

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