Помилка голови підмодуля Git 'посилання - це не дерево'


305

У мене є проект з підмодулем, який вказує на недійсний фіксатор: фіксація підмодуля залишилася локальною, і коли я намагаюся взяти його з іншого репо, я отримую:

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

Я знаю, якою має бути підмодуль HEAD, чи є спосіб змінити це локально, не відштовхуючись від репо, який має на себе зобов'язання 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

Я не впевнений, чи мені зрозуміло ... ось подібну ситуацію я знайшов.


11
"фатально: посилання не є деревом" у посиланні на підмодулі, як правило, означає, що підмодуль здійснює, що батьківське репо, очікує, ще не було висунуто, або вкручене якимось іншим способом. Для нас це заплутане повідомлення про помилку було вирішено просто натисканням на підмодуль, який хтось забув натиснути.
Кріс Москіні

1
@ChrisMoschini - У мене просто було це питання, і це було моє "рішення", я підштовхнув і потягнув головне репо., Але я забув підсунути останнє зобов'язання до репо підмодуля. Дякую!
Ротем

Можливо, ви забули натиснути на останні підмодулі
Хафенкраніч

Відповіді:


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>для створення та оформлення замовлення гілки на комітці або оформлення замовлення потрібної гілки (наприклад, з потрібною фіксацією на кінчику).

Оновіть проект Super

Оформлення замовлення в підмодулі відображається в надпроекті як зміна робочого дерева. Тому нам потрібно поетапно змінити індекс суперпроекту і перевірити результати.

$ 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

Оновлення підмодуля було беззвучним, оскільки підмодуль вже знаходиться у вказаній комісії. Перший розріз показує, що індекс і робоче дерево однакові. Третя різниця показує, що єдиною поетапною зміною є переміщення subпідмодуля до іншого коміту.

Здійснити

git commit

Це робить фіксований запис субмодуля.


Зовні, в

Якщо ви не впевнені, яку команду ви повинні використовувати з підмодулю, ви можете переглянути історію в надпроекті, щоб навести вас. Ви також можете керувати скиданням безпосередньо із суперпроекту.

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

Це та сама ситуація, що і вище. Але цього разу ми зупинимося на тому, щоб виправити це із суперпроекту, а не занурюватися в підмодуль.

Знайдіть Коміт Ерранта Супер-проекту

$ 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

Гаразд, схоже, що в ньому пішло погано ce5d37c, тому ми відновимо підмодуль від його батьківського ( ce5d37c~).

Крім того, ви можете взяти команду підмодуля з тексту виправлення ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) та використати вищезазначений процес "всередину, зовні".

Оформити замовлення в проекті Super

$ git checkout ce5d37c~ -- sub

Це скидає запис субмодуля subдо того, що було зроблено на здійсненні ce5d37c~в надпроекті.

Оновіть підмодуль

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

Оновлення підмодуля пішло нормально (воно вказує на відокремлену ГОЛОВУ).

Перевірте результати

$ 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

Перший diff показує, що subтепер те саме в ce5d37c~. Друга різниця показує, що індекс і робоче дерево однакові. Третя різниця показує, що єдиною поетапною зміною є переміщення subпідмодуля до іншого коміту.

Здійснити

git commit

Це робить фіксований запис субмодуля.


У підході "Зовнішній вигляд" ви могли б з'ясувати, чому "схоже, що це стало погано у ce5d37c?" Які пальці цього, як поганий вчинок?
Гаррет Олбрайт

5
@Garrett: Припущення - e47c0aце зобов’язання, яке не існує в локальному сховищі для sub, все ж, суперпроекти subвказують на цей комітет. Це могло статися тому, що хтось інший, створений e47c0aу своїй копії sub, оновив свій суперпроект, щоб вказати на цю фіксацію, і висунув суперпроект, не натискаючи e47c0aна центральне / спільне сховище для sub. Коли ми витягуємо з центрального / загального супер-проекту ми отримуємо Комміт , що точки subв e47c0a, але ми не можемо «бачити» , що зробити. ce5d37cє підозрюваним, тому що, виходячи з різниці, вона введена e47c0a.
Кріс Джонсен

Досі залишається досить невиразним, де знаходиться специфічний хеш subзберігається в батьківському репо, який має його як підмодуль, і чи можна ним маніпулювати безпосередньо безпосередньо поточній ГОЛОВІ subбезпосередньо, не покладаючись на старіший стан батьків репо, що не завжди може допомогти.
matanster


187

спробуйте це:

git submodule sync
git submodule update

2
Не для мене, на жаль, один з наших підмодулів був націлений на головне сховище git із командою add, тепер у нього виникають проблеми з його скасуванням
Даніель

9
Працював і для мене. Хочеться знати, хоча все-таки.
BenBtg

12
Виявляється, що робити a git submodule syncпотрібно в сценаріях, де URL-адреса дистанційного керування для даного підмодуля змінилася. У нашому випадку ми додали наш підмодуль із публічного репо, а потім змінили URL-адресу на приватну виделку - і потрапили в цей конкретний соління.
Samscam

Наприклад: у мене було встановлено repo (A) з підмодулем, що вказує на моє github repo (B). Я створив гілку в РЕПО, тому що хотів вказати В на чуже релізо github. Трохи боровшись із цим і виконуючи гілку, я переключив репо A назад до майстра, і цю проблему з рішенням repo B. @Lonre Wang виправили.
fbicknel

2
Якщо припустити, що насправді ніхто не накрутив (у такому випадку вам знадобиться відмінна відповідь Кріса Джонсена), відповідь Lonre Wang повинна вирішити проблему, ... ПІДНЯТЬ, що у ваших підмодулях є власні підмодулі (а проблема всередині підмодуля). У цьому випадку вам потрібно вступити в підмодуль, який містить підмодуль з проблемою, і виконати вищевказані команди. Зауважте, що оновлення має - рекурсивний варіант (оновлення підмодуля git - рекурсивне), але синхронізація не робить; вам дійсно потрібно вручну запустити 'git submodule sync' всередині підмодуля, який має проблемний під (під) модуль. Це була моя проблема;).
Карло Вуд

16

Ця помилка може означати, що комісія відсутня в підмодулі. Тобто сховище (A) має підмодуль (B). A хоче завантажити B так, щоб він вказував на певний коміт (у B). Якщо ця комісія якось відсутня, ви отримаєте цю помилку. Однією з можливих причин: посилання на комісію було висунуто в A, але фактичне зобов’язання не було відхилене від B. Тому я б почав з цього місця.

Менш ймовірно, що проблема з дозволами не може бути усунена (можливо, якщо ви використовуєте git + ssh).

Переконайтесь, що шляхи підмодуля виглядають нормально у .git / config та .gitmodules.

Останнє, що потрібно спробувати - всередині каталогу підмодулів: git reset HEAD --hard


3
Я вже пояснював, що в питанні ... саме питання полягало в тому, як його вирішити. І на це вже успішно відповіли майже два роки тому ... Дозволи не мають нічого спільного з цим.
Маурісіо Шеффер

1
Ви це заявили, ви точно не пояснили.
Даніель Цадок

Моя думка, ця відповідь не містить ніякої цінної інформації, я б її видалив.
Маурісіо Шеффер

4
"git reset HEAD --hard" мені теж допоміг ... нічого іншого не працювало. Я спробував і попередні рішення, без кісток. Дякую!
Вергілій

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

Як результат, віддалений користувач не міг знайти віддалений користувач, оскільки вони все ще знаходяться на локальному диску.

Рішення

Поінформуйте людину, яка змінила підмодуль на натиск, тобто

$ cd submodule
$ git push

6

Я отримав цю помилку, коли зробив:

$ git submodule update --init --depth 1

але команда у батьківському проекті вказувала на більш раннє.

Видалення папки підмодуля та запуску:

$ git submodule update --init

НЕ вирішив проблему. Я видалив репо і спробував ще раз без прапора глибини, і воно спрацювало.

Ця помилка трапляється в Ubuntu 16.04 git 2.7.4, але не в Ubuntu 18.04 git 2.17, TODO знаходить точну фіксацію фіксації або версію.


моя команда з тих пір відмовилася від субмодулів у нашому кодовому способі занадто багато клопоту лол
Платон

1
яка ваша альтернатива?
nuzzolilo

@nuzzolilo ми додали username/repo#shaдо package.json, набагато гнучкішим варіантом є організація вашої системи з набором контейнерів для докерів
Платон

3
Це так дратує. --depth=1економить стільки пропускної здатності, коли мені не потрібна історія репо. Якщо хто-небудь коли-небудь знає чи знає, чому це відбувається, я хотів би знати.
i336_

@ i336_ Хоча я не можу пояснити чому, я написав помічник cmake, який допомагає пом'якшити проблему тут: github.com/LMMS/lmms/blob/… . Він використовує deinitпідхід, який вирішує проблему більшу частину часу. У комплекті з системою збірки кінцевий користувач може просто дозволити системі збирання витягнути підмодулі та викопати порушену recursiveкоманду. Досі існують сценарії, коли це порушується, наприклад, підмодуль здійснив силовий поштовх і повністю ліквідував виконання.
tresf

5

Це також може статися, коли у вас є підмодуль, який вказує на сховище, яке було перезавантажено, і дана фіксація "пропала". Хоча фіксація все ще може бути у віддаленому сховищі, вона не знаходиться у відділенні. Якщо ви не можете створити нову гілку (наприклад, не ваш репозиторій), вам не доведеться оновити суперпроект, щоб вказати на нову фіксацію. Крім того, ви можете натиснути одну зі своїх копій підмодулів в інше місце, а потім оновити суперпроект, щоб вказати на це сховище.


5

Можливо, ваша філія не є актуальною, просте рішення, але спробуйте git fetch


2

Ця відповідь призначена для користувачів SourceTree з обмеженим досвідом роботи терміналу.

Відкрийте проблемний підмодуль із проекту Git (суперпроект).

Вилучити та забезпечити прапорець "Вилучити всі теги".

Перезавантажте проект Git.

Це вирішить проблему «посилання не дерево» 9 з десяти разів. Це 1 раз не стане, це виправлення терміналу, як описано у верхній відповіді.


1

Ваша історія підмодуля в будь-якому разі надійно зберігається в підмодулі.

Отже, чому б просто не видалити підмодуль і додати його знову?

В іншому випадку ви спробували вручну редагувати підмодуль HEADабо refs/master/headв ньому.git


1
Це не спрацює, тому що десь є посилання на 2d7cfbd09fc96c04c4c41148d44ed7778add6b43, який є лише в місцевому репо, десь в іншому місці, але не публікується
Маурісіо Шеффер

1

Щоб переконатися, спробуйте оновити gitбінарні файли.

У GitHub для Windows є версія, git version 1.8.4.msysgit.0яка в моєму випадку була проблемою. Оновлення вирішило це.


1

У моєму випадку жодна відповідь вище не вирішує проблему, навіть якщо це хороші відповіді. Тож я розміщую своє рішення (у моєму випадку є два клієнти git, клієнт A і B):

  1. перейдіть до режиму підмодуля:

    cd sub
    
  2. замовлення на майстер:

    git checkout master
    
  3. відновлення коду фіксації, який можуть бачити обидва клієнта

  4. поверніться до батьківського режисура:

  5. зобов’язатись опанувати

  6. змінити на іншого клієнта , зробити rebaseще раз.

  7. нарешті це працює нормально зараз! Можливо, втратите пару комітетів, але це працює.

  8. FYI, не намагайтеся видалити свій підмодуль, він залишатиметься .git/modulesтам і не може прочитати цей підмодуль знову, якщо не буде реагувати локальний.


1

Щоб синхронізувати git repo з головою підмодуля, якщо це дійсно те, що ви хочете, я виявив, що видалення підмодуля та його повторне читання дозволяє уникнути повороту з історією. На жаль, для видалення підмодуля потрібен злом, а не одна команда git, але виконана.

Кроки, які я дотримувався, щоб видалити підмодуль, натхненний https://gist.github.com/kyleturner/1563153 :

  1. Запустити git rm - кешований
  2. Видаліть відповідні рядки з файлу .gitmodules.
  3. Видаліть відповідний розділ із .git / config.
  4. Видаліть не відстежені файли підмодуля.
  5. Видалити каталог .git / модулі /

Знову ж таки, це може бути корисно, якщо все, що ви хочете, - це знову вказати на голову підмодуля, і ви не ускладнювали речі, зберігаючи локальну копію підмодуля неушкодженою. Це передбачає, що у вас є підмодуль "правильний" як власне репо, де б воно не було, і ви просто хочете повернутися до належного включення його як підмодуля.

Примітка. Завжди робіть повну копію свого проекту, перш ніж займатися подібними маніпуляціями або будь-якою командою git за рамки простої фіксації чи натискання. Я б радив це, як і всі інші відповіді, і як загальне керівництво щодо суті.


1

Я просто натрапив на цю проблему, і жодне з цих рішень не працювало на мене. Те, що виявилося вирішенням моєї проблеми, насправді набагато простіше: оновити Git. Моя була 1.7.1, і після того, як я оновив її до 2.16.1 (останнє), проблема пройшла безслідно! Здогадуюсь, я залишаю це тут, сподіваюся, що це комусь допоможе.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.