Подмодуль Git находится в состоянии "отсоединенной головки" после обновления клонирования и подмодуля

Когда я клонирую свой репо git, один из подмодулей находится в ветки со странным именем, что, я думаю, означает, что у него есть " отсоединенная голова" (я даже не уверен что это значит).

Если я проверяю свою основную ветвь для подмодуля, тогда запустите "git submodule update --init --recursive", это произойдет снова.

Кто-нибудь знает, что происходит?

Ответ 1

Содержимое каталогов git хранится в манифесте простого текстового файла (например, списки каталогов), называемые деревьями, которые выглядят следующим образом: где капли - это содержимое файлов, а деревья - еще больше деревьев, подобных этому:

100644 blob 0c31be662540ce902cee106f86bfdeef519fc662    .gitignore
100644 blob 1d364edf530c2238e79162bf2d9f30c2af610347    .gitmodules
040000 tree fc6bc39202ec20228e9135cd426110c558b625cd    foo
040000 tree 2f9fc460f3a2370ed45b39b2bcaaf9b6e746b823    bar

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

100644 blob 0c31be662540ce902cee106f86bfdeef519fc662    .gitignore
100644 blob 1d364edf530c2238e79162bf2d9f30c2af610347    .gitmodules
040000 tree fc6bc39202ec20228e9135cd426110c558b625cd    foo
040000 commit 2f9fc460f3a2370ed45b39b2bcaaf9b6e746b823  bar

Обратите внимание, что вместо того, чтобы bar является деревом, теперь он является фиксацией (в подмодуле). Это все git хранит о субмодуле на уровне дерева/фиксации, поэтому он не может знать, в какую ветвь была включена фиксация. На самом деле сохранение имен веток не может быть выполнено. Они могут измениться. Кроме того, если вы проверите старую фиксацию в своем репо, которая также должна отбросить подмодуль, если ветвь вернется в подмодуль? Это заставило бы коммиты после этого нового местоположения ветки на незарегистрированную территорию.

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

Ответ 2

Подмодуль всегда извлекается как отдельный заголовок (см. " Почему git отсоединил мою голову? "), Поскольку индекс родительского репо содержит только SHA1 в качестве специальной записи в своем индексе, как объяснил ответ Гэри Фикслера.

Даже если вы сконфигурируете свой подмодуль, чтобы он следовал за веткой (или преобразовал существующий подмодуль, чтобы следовать за веткой), git submodule update --remote будет git submodule update --remote последний SHA1 этой удаленной ветки, но результатом по умолчанию будет отдельный HEAD.
Только добавив --merge или --rebase к этой команде (git submodule update --remote (--merge / --rebase)), вы получите git submodule update --remote (--merge / --rebase), как видно из ответа Симбы): по умолчанию master ветка.

Если вы не обновляете этот путь (git submodule update --remote (--merge / --rebase)), то вам нужно зайти в этот подмодуль и создать там ветку.

Если вы хотите внести свой вклад в упомянутый подмодуль (делать в нем новые коммиты), будет хорошей идеей создать новую ветку.

cd mySubmodule
git checkout -b aNewBranch
# work
git add .
git commit -m "new commits"
git push -u origin aNewBranch

# record the new submodule state in the parent repo:
cd ..
git add mySubmodule
git commit -m "new state of mySubmodule"
git push

Примечание для Git 2.16 (Q1 2018): " git checkout --recursive " может перезаписывать и перематывать историю ветки, которая оказывается извлеченной в репозиториях подмодулей, что может быть нежелательно.
Отсоедините HEAD но все же разрешите рекурсивную проверку в таком случае успешно.

Смотрите коммит 57f22bf (28 июля 2017 г.) и коммит 3ef2538 (24 июля 2017 г.) Стефана Беллера (stefanbeller).
(Объединено с Junio C Hamano - gitster - в коммите 0b75572, 06 декабря 2017 г.)

рекурсивные подмодули: отсоединить HEAD от нового состояния

Когда подмодуль находится в ветки и в его суперпроекте выполняется рекурсивная проверка, ветвь подмодуля обновляется до того, что проверяет суперпроект.
Это очень неожиданно в текущей модели Git, так как, например, " submodule update " всегда отсоединяет подмодуль HEAD.

Несмотря на то, что в будущем планируется отключить подмодуль HEADS, текущее поведение действительно плохое, так как оно не соответствует ожиданиям пользователей и не проверяет потерю коммитов (только для восстановления через reflog).

Отсоединяйте ГОЛОВКУ безоговорочно в подмодуле при его обновлении.

Ответ 3

Для пользователей Sourcetree - вы будете наблюдать такое же поведение - клон даст вам подмодули в отдельном состоянии. Поскольку VonC упоминает в своем ответе, если вы хотите внести вклад в подмодуль, вам нужно выполнить некоторые дополнительные шаги.

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

Вы можете либо открыть каждый подмодуль, либо вручную проверить их соответствующие ветки, либо создать собственное действие для него (рекурсивно!):

enter image description here

Script для запуска

cmd

Параметры

/c %LOCALAPPDATA%\Atlassian\SourceTree\git_local\bin\sh.exe --login -i -c "git pull; git submodule foreach -q --recursive 'toplevel=\"$(git rev-parse --show-toplevel)\"; branch=\"$(git config -f $toplevel/.gitmodules submodule.$name.branch)\"; [ \"$branch\" = \"\" ] && branch=master; git checkout $branch; git fetch; git merge FETCH_HEAD;'"""

Это проверит любые подмодули в вашем проекте и проверит ветку, на которую они указывают (или мастер, если они не указывают ветку). Он рекурсивный, поэтому любые подмодули, содержащие подмодули, также будут обрабатываться.

Как я узнал в более раннем сообщении, требуется дополнительная пара кавычек на конце.

Ответ 4

Добавление параметра branch в .gitmodule НЕ связано с отсоединенным поведением подмодулей вообще.

Из git submodule --help отключение HEAD является поведением по умолчанию git submodule update --remote.

Во-первых, нет необходимости указывать отслеживаемую ветвь. origin/master является веткой по умолчанию для отслеживания.

--remote

Вместо того, чтобы использовать суперпроект, записанный SHA-1, для обновления субмодуля, используйте статус ветки удаленного отслеживания субмодуля. Используется удаленный филиал (branch.<name>.remote), по branch.<name>.remote используется origin. Удаленная ветвь по умолчанию использовала master.

Зачем

Так почему же HEAD отключается после update? Потому что по умолчанию в submodule.$name.update используется checkout.

--checkout

Оформить коммит, записанный в суперпроекте на отдельном HEAD в субмодуле. Это поведение по умолчанию, основное использование этого параметра - переопределение submodule.$name.update когда установлено значение, отличное от checkout.

Как

Если вы хотите, чтобы субмодуль автоматически объединялся с удаленной ветвью, используйте --merge или --rebase.

--merge

Эта опция действительна только для команды обновления. Объединить фиксацию, записанную в суперпроекте, с текущей веткой субмодуля. Если эта опция задана, подмодуль HEAD не будет отсоединен.

--rebase

Перебазировать текущую ветвь на коммит, записанный в суперпроекте. Если эта опция задана, подмодуль HEAD не будет отсоединен.

Все, что вам нужно сделать, это,

git submodule update --remote --merge
# or
git submodule update --remote --rebase

Также есть возможность сделать --merge или --rebase поведением по умолчанию для git submodule update, установив submodule.$name.update для merge или rebase.

Вот пример того, как .gitmodule поведение обновления по умолчанию для обновления субмодуля в .gitmodule.

[submodule "bash/plugins/dircolors-solarized"]
    path = bash/plugins/dircolors-solarized
    url = https://github.com/seebi/dircolors-solarized.git
    update = merge # <-- this is what you need to add

Весь мой ответ основан на руководстве. git submodule --help.