Почему git говорит «Изменения не подготовлены для фиксации» и указывает папку подмодуля? - PullRequest
0 голосов
/ 28 января 2019

У меня есть подмодуль git внутри другого модуля, добавленный с помощью git submodule add <...> (команда отправлена ​​из родительского репо), поэтому файл .gitmodules автоматически создается внутри родительского репо.

Предположим, я внес измененияк субмодулю (отредактируйте: и выполните , а не передайте эти изменения), затем вернитесь обратно к родительскому модулю и выполните git add -A, а затем git status, он говорит: «Изменения не подготовлены для фиксации: имя подмодуля dir ... etc ".

Я думал, что git прочитает файл .gitmodules (который сгенерировал родительский git!), поймет его каталог подмодуля git и, следовательно, не упомянет его неизмененный статус, когдаЯ спрашиваю у родителя его статус?

Ответы [ 2 ]

0 голосов
/ 28 января 2019

Здесь происходит то, что ваш репозиторий субмодулей находится на коммите, отличном от хеш-идентификатора, записанного в суперпроекте.Ваш git status, запущенный в суперпроекте, говорит вам об этом, не меняя его, и ваш git add -A, по-видимому, тоже не изменил.

Эта последняя часть кажется неправильной.Когда я делаю что-то подобное, а затем использую git add -A, я получаю:

Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

        modified:   [submodule path]

Если я затем запускаю еще две команды, все возвращается назад, как я и ожидал:

$ git reset
Unstaged changes after reset:
M       [submodule path]
$ git submodule update
Submodule path [path]: checked out '[hash]'
$ git status
On branch ...
nothing to commit, working tree clean

подозреваю , что вы внесли некоторые изменения в подмодуль, но никогда не вносили их там.)

Что происходит, с мелкими деталями, которые позволят вам диагностировать проблему

У нас есть один репозиторий Git, называемый суперпроектом , который управляет вторым репозиторием, называемым подмодулем .Суперпроект на самом деле имеет три отдельные ручки управления, одна из которых присутствует в каждом коммите, и поэтому также находится в index (так как индекс контролирует то, что будет входить в next commit).

Одной из этих ручек управления является файл, который вы упомянули, .gitmodules.Он сообщает суперпроекту , как клонировать подмодуль , если подмодуль еще не git clone d.Как только субмодуль клонируется, его основная работа завершена.

Второй - это ваш .git/config файл.Он содержит информацию, скопированную из файла .gitmodules, которую вы можете обновить при необходимости, если файл .gitmodules не совсем подходит для ваших собственных целей (который может отличаться от тех, кто отвечает за файл .gitmodules),Любые настройки в .git/config переопределяют настройки в .gitmodules.В противном случае эти два места для установки параметров по существу эквивалентны.

Последнее является причиной возникновения проблемы.Чтобы подмодуль стал извлеченным в ваше рабочее дерево и, следовательно, был полезен для вас, Git, который контролирует суперпроект, запускает второй набор команд Git.В общем, вы можете запустить:

git submodule update --init

, чтобы получить подмодуль для проверки (хотя, если вы используете git clone --recursive, Git сделает это за вас).

На этом этапе суперпроектGit создал почти пустой каталог с правильным путем.(Каталог содержит файл .git с именем пути к клонированному репозиторию, либо в старые времена, либо с использованием режима обратной совместимости старого стиля, содержит сам фактический каталог .git.) Суперпроект Git chdir s вэтот каталог и сообщает подмодулю Git:

  • run git checkout <em>hash</em>

Как только это произошло, путь заполнен файлами, извлеченными из коммита, чей ID равен hash, который в основном делает внешний Git (суперпроект) "готовым" к файлам.Но есть побочный эффект, поскольку подмодуль сам по себе является полным Git-репозиторием со всем, что это означает.

В частности, подпроект имеет свой собственный HEAD.Это HEAD теперь отсоединено , а текущая фиксация хранилища подмодуля hash, так что это находится в индексе и рабочем дереве подмодуля, что, конечно,мы хотели: рабочим деревом подмодуля является путь в суперпроекте, куда идут все файлы подмодуля.

Но есть интересный вопрос, на который нужно ответить: Где суперпроект Git получил хеш-идентификатор? Ответ таков: он хранится в каждом снимке - ну, каждый снимок, который использует субмодуль - в суперпроекте, так же, как каждый снимок имеет полную, полную копию каждого файла.Чтобы это произошло, индекс для суперпроекта содержит специальную запись типа gitlink .

. Эта запись gitlink в индексе суперпроекта сообщает суперпроекту, какой хэш-идентификатор следует предоставлять подмодулю Git всякий раз, когдасуперпроект сообщает субмодулю Git: проверить какой-то конкретный коммит .

Если вы вручную войдете в подмодуль и git checkout имя ветки или любой другой коммит по хеш-идентификатору, репозиторий подмодуля HEAD изменится.Он либо присоединяется к имени ветви, либо указывает на другой коммит, все еще находящийся в режиме detached-HEAD.

В этот момент субмодуль и суперпроект не синхронизированы .Суперпроект Git пока ничего не делает.Вы контролируете, вы выбираете, какой коммит вы хотите.Вы даже можете делать новые коммиты и git push их в какой-то апстрим.После того, как вы выполнили все действия по фиксации и git checkout, которые хотите, и все правильно расположили, вы должны вылезти из рабочего дерева подмодуля обратно в свой суперпроект.

Теперь git statusи git diff по умолчанию - здесь также есть тонна управляющих ручек - скажет вам, что суперпроект вызывает некоторый хеш H , но у подмодуля есть какой-то другой хеш S проверено.(Они могут или не могут также сказать вам, нужно ли самому подмодулю совершить коммит, если вы установите для этого регуляторы управления.) Если вы хотите, чтобы ваш следующий коммит суперпроекта записывал, в gitlink для этого подмодуля этот новый хеш коммита S , вы запускаете:

git add path-to-submodule

(или git add -A должен сделать то же самое, вот почему это озадачивает).Это обновит gitlink в вашем индексе для записи хеш-идентификатора S , а не H , так что следующий коммит суперпроекта по команде git submodule update сообщит субмодулю Git: проверить коммит S, как ваш отдельный HEAD .

Как только индекс в суперпроекте совпадает с HEAD в фактическом извлеченном подмодуле, подмодуль не будет быть внесенным в список изменений, не подготовленных для фиксации .Если хеш в gitlink в индексе не совпадает с хешем в gitlink в HEAD, git status будет перечислять путь подмодуля в изменениях для фиксации .

0 голосов
/ 28 января 2019

и, следовательно, не упоминать его статус unstaged, когда я спрашиваю у родителя его статус?

Он все равно будет сообщать об изменениях в подмодулях, если вы не используете (с Git1.7.2 или более ):

Вы можете увидеть оригинальное обсуждение (еще в 2010 году для Git 1.7.x) здесь , что привело к этой функции:

Кстати, я думаю, что маршрут действий сделает полученный git внутренне согласованным, так как все по умолчанию будет сообщать подмодулям с неотслеживаемыми путями в своем рабочем дереве как грязные.

  • В разделе «Untracked» вывода «git status» мы перечисляем неотслеживаемый путь в суперпроекте (т. Е. Тот, в котором был запущен «git status»), чтобы напомнить пользователю, что путь может быть новым файломзабыли добавить (если, конечно, он игнорируется).
    Но это не делает рабочий трегрязный.

  • Если у вас есть неотслеживаемый путь в подмодуле:

    • подмодуль отображается в разделе «Изменено, но не обновлено».
      Это также делает грязное рабочее дерево суперпроекта, даже если рабочее дерево подмодуля имеет не .

    • "git diff" выходна уровне суперпроекта показывает, что подмодуль имеет модификации (то есть отображается «-dirty»), но при запуске внутри подмодуля изменения не отображаются.

Я думаю, что это неправильный дизайн на уровне пользовательского интерфейса;сообщать о неотслеживаемом и незарегистрированном пути как о потенциальной ошибке, чтобы напомнить пользователю, это хорошо, но текущий способ "status" и "diff" делает это не имеет большого смысла для меня.

...