Tham chiếu đầu của mô đun con Git 'không phải là cây'


305

Tôi có một dự án với một mô hình con đang trỏ đến một cam kết không hợp lệ: cam kết mô hình con vẫn là cục bộ và khi tôi cố gắng tìm nạp nó từ một repo khác tôi nhận được:

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

Tôi biết những gì các HEAD submodule nên được, là có cách nào tôi có thể thay đổi điều này tại địa phương, mà không đẩy từ repo mà không có cam kết 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

Tôi không chắc là mình có rõ không ... đây là một tình huống tương tự tôi đã tìm thấy.


11
"gây tử vong: tham chiếu không phải là một cây" trong tham chiếu đến các mô hình con dường như thường có nghĩa là cam kết của mô hình con mà repo cha mẹ mong đợi chưa được đẩy hoặc bị vặn theo một cách khác. Đối với chúng tôi, thông báo lỗi khó hiểu này đã được giải quyết bằng cách chỉ cần nhấn một mô hình con người nào đó quên đẩy.
Chris Moschini

1
@ChrisMoschini - Tôi vừa gặp vấn đề đó, và đó là "giải pháp" của tôi, tôi đã đẩy và kéo repo chính., Nhưng tôi đã quên đẩy cam kết cuối cùng của mình vào repo của mô hình con. Cảm ơn!
Rotem

Có thể bạn đã quên đẩy các cam kết mô hình con mới nhất
Hafenkranich

Câu trả lời:


378

Giả sử kho lưu trữ của mô hình con có chứa một cam kết bạn muốn sử dụng (không giống như cam kết được tham chiếu từ trạng thái hiện tại của siêu dự án), có hai cách để thực hiện.

Việc đầu tiên đòi hỏi bạn phải biết cam kết từ mô hình con mà bạn muốn sử dụng. Nó hoạt động từ các mạng bên trong, ngoài ra bằng cách điều chỉnh trực tiếp mô hình con sau đó cập nhật siêu dự án. Công cụ thứ hai hoạt động từ các bên ngoài, trong cộng đồng bằng cách tìm ra cam kết của siêu dự án đã sửa đổi mô hình con và sau đó đặt lại chỉ mục của siêu dự án để tham chiếu đến một cam kết mô hình con khác.

Trái ngược

Nếu bạn đã biết mà phạm bạn muốn submodule để sử dụng, cdđến submodule, hãy kiểm tra các cam kết mà bạn muốn, sau đó git addgit commitnó trở lại trong các siêu dự án.

Thí dụ:

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

Rất tiếc, ai đó đã thực hiện một cam kết siêu dự án đề cập đến một cam kết chưa được công bố trong mô hình con sub. Bằng cách nào đó, chúng tôi đã biết rằng chúng tôi muốn mô hình con được cam kết 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. Đến đó và kiểm tra nó trực tiếp.

Thanh toán trong mô hình con

$ 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 ..

Vì chúng tôi đang kiểm tra một cam kết, điều này tạo ra một ĐẦU tách rời trong mô hình con. Nếu bạn muốn chắc chắn rằng mô hình con đang sử dụng một nhánh, thì hãy sử dụng git checkout -b newbranch <commit>để tạo và kiểm tra một nhánh tại cam kết hoặc kiểm tra nhánh mà bạn muốn (ví dụ: một nhánh có cam kết mong muốn ở đầu).

Cập nhật siêu dự án

Một kiểm tra trong mô hình con được phản ánh trong siêu dự án như là một sự thay đổi cho cây làm việc. Vì vậy, chúng ta cần giai đoạn thay đổi chỉ số của siêu dự án và xác minh kết quả.

$ git add sub

Kiểm tra kết quả

$ 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

Bản cập nhật mô hình con im lặng vì mô hình con đã ở mức cam kết đã chỉ định. Khác biệt đầu tiên cho thấy chỉ số và worktree là như nhau. Khác biệt thứ ba cho thấy sự thay đổi theo giai đoạn duy nhất là di chuyển submô hình con sang một cam kết khác.

Cam kết

git commit

Điều này cam kết mục nhập mô hình con cố định.


Ngoài vào trong

Nếu bạn không chắc chắn nên sử dụng cam kết nào từ mô hình con, bạn có thể xem lịch sử trong siêu dự án để hướng dẫn bạn. Bạn cũng có thể quản lý thiết lập lại trực tiếp từ siêu dự án.

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

Đây là tình huống tương tự như trên. Nhưng lần này chúng tôi sẽ tập trung vào việc sửa nó từ siêu dự án thay vì nhúng vào mô hình con.

Tìm Cam kết Errant của siêu dự án

$ 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, có vẻ như nó đã bị hỏng ce5d37c, vì vậy chúng tôi sẽ khôi phục mô hình con từ cha mẹ của nó ( ce5d37c~).

Ngoài ra, bạn có thể lấy cam kết của mô hình con từ văn bản vá ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) và sử dụng quy trình trên bên trong, ngoài quy trình Thay thế.

Thanh toán trong siêu dự án

$ git checkout ce5d37c~ -- sub

Điều này đặt lại mục nhập mô hình con cho subnhững gì nó đã được cam kết ce5d37c~trong siêu dự án.

Cập nhật mô hình con

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

Bản cập nhật mô hình con đã hoạt động tốt (nó chỉ ra một ĐẦU tách rời).

Kiểm tra kết quả

$ 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

Các khác biệt đầu tiên cho thấy subbây giờ là như nhau trong ce5d37c~. Khác biệt thứ hai cho thấy chỉ số và worktree là như nhau. Khác biệt thứ ba cho thấy sự thay đổi theo giai đoạn duy nhất là di chuyển submô hình con sang một cam kết khác.

Cam kết

git commit

Điều này cam kết mục nhập mô hình con cố định.


Trong cách tiếp cận "Bên ngoài, Trong", bạn có thể làm sáng tỏ lý do tại sao "có vẻ như nó bị hỏng trong ce5d37c?" Những ngón tay mà một như là cam kết xấu?
Garrett Albright

5
@Garrett: Giả định là e47c0amột cam kết không tồn tại trong kho lưu trữ cục bộ sub, nhưng các siêu dự án subchỉ ra cam kết đó. Điều này có thể đã xảy ra vì một người khác được tạo e47c0atrong bản sao của họ sub, đã cập nhật siêu dự án của họ để chỉ ra cam kết đó và đẩy siêu dự án mà không đẩy e47c0avào kho lưu trữ trung tâm / chia sẻ sub. Khi chúng tôi rút ra từ siêu dự án trung tâm / chia sẻ, chúng tôi nhận được một cam kết trỏ subđến e47c0a, nhưng chúng tôi không thể thấy được cam kết đó. ce5d37clà nghi ngờ bởi vì, dựa trên khác biệt, nó được giới thiệu e47c0a.
Chris Johnsen

Nó vẫn còn khá mơ hồ, nơi băm cụ thể subđược lưu giữ trong repo cha mẹ có nó như là một mô hình con, và liệu nó có thể được thao tác trực tiếp với Head hiện tại hay subkhông, mà không phụ thuộc vào trạng thái cũ của cha mẹ repo, có thể không luôn luôn giúp đỡ.
matanster


187

thử cái này:

git submodule sync
git submodule update

2
Thật không may cho tôi, một trong những mô hình con của chúng tôi đã được kho lưu trữ git chính nhắm mục tiêu bằng lệnh add, hiện đang gặp sự cố khi hoàn tác nó
Daniel

9
Làm việc cho tôi quá. Rất muốn biết tại sao mặc dù.
BenBtg

12
Hóa ra việc thực hiện git submodule synclà cần thiết trong các tình huống trong đó URL của điều khiển từ xa cho một mô hình con đã cho đã thay đổi. Trong trường hợp của chúng tôi, chúng tôi đã thêm mô hình con của chúng tôi từ một repo công khai và sau đó thay đổi URL thành một ngã ba riêng - và đưa mình vào dưa chua đặc biệt này.
Samscam

Ví dụ: Tôi đã có một repo (A) được thiết lập với một mô hình con trỏ đến repo github của tôi (B). Tôi đã tạo một nhánh trong repo A vì tôi muốn trỏ B vào repo github của người khác. Sau một chút vật lộn với điều đó và cam kết chi nhánh, tôi đã chuyển repo A của mình trở lại thành chủ và gặp vấn đề này với giải pháp của repo B. @Lonre Wang đã khắc phục nó.
fbicknel

2
Giả sử không có ai THỰC SỰ làm hỏng (trong trường hợp bạn cần câu trả lời xuất sắc của Chris Johnsen), câu trả lời của Lonre Wang sẽ khắc phục vấn đề, ... KHÔNG GIỚI HẠN các mô hình con của bạn có các mô đun con của riêng họ (và vấn đề nằm trong mô hình con). Trong trường hợp đó, bạn cần cd vào mô hình con có mô hình con có vấn đề và thực hiện các lệnh trên. Lưu ý rằng bản cập nhật có tùy chọn --recursive (git subodule update --recursive), nhưng đồng bộ hóa thì không; bạn thực sự phải chạy thủ công 'git subodule sync' bên trong mô hình con có mô-đun phụ (phụ) có vấn đề. Đây là vấn đề của tôi;).
Carlo Wood

16

Lỗi này có thể có nghĩa là một cam kết bị thiếu trong mô hình con. Nghĩa là, kho lưu trữ (A) có một mô hình con (B). A muốn tải B để nó trỏ đến một cam kết nhất định (trong B). Nếu cam kết đó bằng cách nào đó bị thiếu, bạn sẽ gặp lỗi đó. Một khi nguyên nhân có thể: tham chiếu đến cam kết đã được đẩy trong A, nhưng cam kết thực tế không được đẩy từ B. Vì vậy, tôi bắt đầu từ đó.

Ít có khả năng, có vấn đề về quyền và cam kết không thể được rút ra (có thể nếu bạn đang sử dụng git + ssh).

Hãy chắc chắn rằng các đường dẫn mô hình con trông ổn trong .git / config và .gitmodules.

Một điều cuối cùng để thử - bên trong thư mục mô hình con: git reset HEAD --hard


3
Tôi đã giải thích rằng trong câu hỏi ... chính câu hỏi là làm thế nào để giải quyết nó. Và nó đã được trả lời thành công gần hai năm trước ... Quyền không liên quan gì đến việc này.
Mauricio Scheffer

1
Bạn đã nói điều đó, bạn chắc chắn đã không giải thích nó.
Daniel Tsadok

Quan điểm của tôi là, câu trả lời này không thêm bất kỳ thông tin có giá trị nào, tôi sẽ xóa nó.
Mauricio Scheffer

4
"Git reset HEAD --hard" cũng giúp tôi ... không có gì khác hoạt động. Tôi đã thử các giải pháp trước đó quá, không có xúc xắc. Cảm ơn!
Virgil

1
Mỗi chủ đề là thế giới nhỏ bé của riêng mình trực tuyến. Những gì bạn nói đại diện cho bạn - bạn không thể mong đợi rằng mọi người sẽ nghiên cứu lịch sử cá nhân của bạn để cố gắng đóng khung ý kiến ​​của bạn trong bối cảnh mang lại cho bạn sự tôn trọng mà bạn mong muốn. Hãy tử tế, tôn trọng và bạn sẽ không cần phải yêu cầu mọi người hiểu về những điều kỳ quặc của bạn. Nếu bạn có thể đọc bình luận của bạn từ một bối cảnh trung lập, như một người ngoài cuộc, bạn sẽ hiểu những lời chỉ trích của tôi.
Stablesog

10

Nguyên nhân có thể

Điều này có thể xảy ra khi:

  1. Submodule (s) đã được chỉnh sửa tại chỗ
  2. Submodule (s) đã cam kết, cập nhật hàm băm của mô hình con được trỏ đến
  3. Submodule (s) không được đẩy .

ví dụ như một cái gì đó như thế này đã xảy ra:

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

Nên có mô hình con đẩy vào thời điểm này.

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

Do đó, người dùng từ xa không thể tìm thấy các cam kết bị thiếu vì chúng vẫn còn trên đĩa cục bộ.

Giải pháp

Thông báo cho người đã sửa đổi mô hình con để đẩy, tức là

$ cd submodule
$ git push

6

Tôi đã gặp lỗi này khi tôi đã làm:

$ git submodule update --init --depth 1

nhưng cam kết trong dự án mẹ đã chỉ vào một cam kết trước đó.

Xóa thư mục mô hình con và chạy:

$ git submodule update --init

KHÔNG giải quyết vấn đề. Tôi đã xóa repo và thử lại mà không có cờ độ sâu và nó hoạt động.

Lỗi này xảy ra trong Ubuntu 16.04 git 2.7.4, nhưng không phải trên Ubuntu 18.04 git 2.17, TODO tìm thấy bản sửa lỗi hoặc phiên bản sửa lỗi chính xác.


Nhóm của tôi đã từ bỏ các mô đun con theo cách mã của chúng tôi quá nhiều rắc rối lol
Plato

1
lựa chọn của bạn là gì?
nuzzolilo

@nuzzolilo chúng tôi đã thêm vào pack.json username/repo#sha, một tùy chọn linh hoạt hơn nhiều là tổ chức hệ thống của bạn với một bộ container docker
Plato

3
Điều này thật khó chịu. --depth=1tiết kiệm rất nhiều băng thông khi tôi không cần lịch sử repo. Nếu bất cứ ai từng tìm thấy hoặc biết lý do tại sao điều này xảy ra, tôi rất muốn biết.
i336_

@ i336_ Mặc dù tôi không thể giải thích lý do tại sao, tôi đã viết một trình trợ giúp cmake giúp giảm thiểu vấn đề ở đây: github.com/LMMS/lmms/blob/ . Nó sử dụng một deinitcách tiếp cận để khắc phục vấn đề phần lớn thời gian. Khi đi kèm với một hệ thống xây dựng, người dùng cuối chỉ có thể để hệ thống xây dựng tìm nạp các mô hình con và bỏ recursivehoàn toàn lệnh bị hỏng . Vẫn có những kịch bản mà sự phá vỡ này, chẳng hạn như mô hình con đã thực hiện một lực đẩy và xóa sạch hoàn toàn cam kết.
tresf

5

Điều này cũng có thể xảy ra khi bạn có một mô hình con trỏ đến một kho lưu trữ đã bị loại bỏ và cam kết đã cho là "biến mất". Mặc dù cam kết vẫn có thể nằm trong kho lưu trữ từ xa, nhưng nó không nằm trong một nhánh. Nếu bạn không thể tạo một chi nhánh mới (ví dụ không phải kho lưu trữ của bạn), bạn sẽ bị mắc kẹt với việc phải cập nhật siêu dự án để trỏ đến một cam kết mới. Ngoài ra, bạn có thể đẩy một trong các bản sao của các mô hình con ở nơi khác và sau đó cập nhật siêu dự án để trỏ đến kho lưu trữ đó.


5

Chi nhánh của bạn có thể không cập nhật, một giải pháp đơn giản nhưng hãy thử git fetch


2

Câu trả lời này dành cho người dùng SourceTree với trải nghiệm git thiết bị đầu cuối hạn chế.

Mở mô hình con có vấn đề từ bên trong dự án Git (siêu dự án).

Tìm nạp và đảm bảo 'Tìm nạp tất cả các thẻ' được chọn.

Rebase kéo dự án Git của bạn.

Điều này sẽ giải quyết vấn đề 'tham chiếu không phải là cây' 9 trên 10 lần. Đó là 1 lần nó sẽ không, là một sửa chữa thiết bị đầu cuối như được mô tả bởi câu trả lời hàng đầu.


1

Lịch sử mô đun con của bạn vẫn được bảo tồn một cách an toàn trong git mô đun con.

Vì vậy, tại sao không chỉ xóa các mô hình con và thêm nó một lần nữa?

Mặt khác, bạn đã thử chỉnh sửa thủ công HEADhoặc refs/master/headbên trong mô hình con.git


1
Điều này sẽ không hoạt động, bởi vì ở đâu đó có một tài liệu tham khảo đến 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 chỉ có trong repo địa phương ở một nơi khác, nhưng không được xuất bản
Mauricio Scheffer

1

Để chắc chắn, hãy thử cập nhật gitnhị phân của bạn .

GitHub cho Windows có phiên bản git version 1.8.4.msysgit.0mà trong trường hợp của tôi là sự cố. Cập nhật đã giải quyết nó.


1

Trong trường hợp của tôi, không có câu trả lời nào ở trên giải quyết được vấn đề ngay cả khi chúng là câu trả lời tốt. Vì vậy, tôi đăng giải pháp của mình (trong trường hợp của tôi có hai khách hàng git, khách hàng A và B):

  1. đi đến thư mục con của mô hình con:

    cd sub
    
  2. kiểm tra để làm chủ:

    git checkout master
    
  3. rebase đến một mã xác nhận mà cả hai khách hàng có thể thấy

  4. quay trở lại thư mục của cha mẹ:

  5. cam kết làm chủ

  6. đổi sang khách hàng khác làm rebaselại.

  7. cuối cùng nó hoạt động tốt bây giờ! Có thể mất một vài cam kết nhưng nó hoạt động.

  8. FYI, đừng cố gắng loại bỏ mô hình con của bạn, nó sẽ vẫn .git/modulesở đó và không thể thực hiện lại mô hình con này một lần nữa, trừ khi phản ứng cục bộ.


1

Để đồng bộ repo git với đầu của mô hình con, trong trường hợp đó thực sự là những gì bạn muốn, tôi thấy rằng việc loại bỏ mô hình con và sau đó thực hiện lại để tránh sự mày mò về lịch sử. Thật không may, loại bỏ một mô hình con yêu cầu hack hơn là một lệnh git duy nhất, nhưng có thể thực hiện được.

Các bước tôi đã làm theo để loại bỏ mô hình con, lấy cảm hứng từ https://gist.github.com/kyleturner/1563153 :

  1. Chạy git rm - đã đóng
  2. Xóa các dòng có liên quan từ tệp .gitmodules.
  3. Xóa phần có liên quan khỏi .git / config.
  4. Xóa các tập tin mô hình con chưa được đóng gói.
  5. Xóa thư mục .git / mô-đun /

Một lần nữa, điều này có thể hữu ích nếu tất cả những gì bạn muốn là chỉ vào đầu của mô hình con một lần nữa và bạn không có những điều phức tạp bằng cách giữ nguyên bản sao của mô hình con. Nó giả định rằng bạn có mô hình con "đúng" như là repo của chính nó, bất kể nguồn gốc của nó là gì, và bạn chỉ muốn quay lại đúng cách bao gồm nó như là một mô hình con.

Lưu ý: luôn tạo một bản sao đầy đủ của dự án của bạn trước khi tham gia vào các loại thao tác này hoặc bất kỳ lệnh git nào ngoài cam kết hoặc đẩy đơn giản. Tôi cũng khuyên rằng với tất cả các câu trả lời khác, và như một hướng dẫn chung.


1

Chỉ vấp phải vấn đề này, và không có giải pháp nào trong số này có hiệu quả với tôi. Điều hóa ra là giải pháp cho vấn đề của tôi thực sự đơn giản hơn nhiều: nâng cấp Git. Của tôi là 1.7.1, và sau khi tôi nâng cấp nó lên 2.16.1 (mới nhất), vấn đề đã biến mất không một dấu vết! Đoán tôi để nó ở đây, hy vọng nó sẽ giúp được ai đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.