Во-первых, давайте попробуем прояснить некоторые вещи здесь. Это сложно, потому что когда вы работаете с Git самостоятельно, это сложно. Когда вы добавляете второй репозиторий Git, в который вы git push
делаете свои собственные коммиты, и из которого вы git fetch
делаете новые коммиты других людей, , то также усложняется. Подмодуль - это не что иное, как третий Git-репозиторий, и этот третий Git-репозиторий имеет четвертый Git-репозиторий, в который вы, возможно, можете git push
свои собственные коммиты, и из которого вы можетеgit fetch
новые коммиты других людей. Таким образом, мы прыгаем прямо в ситуацию, в которой есть по крайней мере четыре репозитория Git, все они несколько независимы друг от друга.
Мы могли бы попытаться рисовать картинки, но даже картинкибудет немного грязноКак мы можем поддерживать четыре хранилища прямо? У Git есть имена для двух из них: два, с которыми вы работаете напрямую, сами. Одним из них является суперпроект , в котором вы работаете git diff
и видите:
diff --git a/submodule-path b/submodule-path
index 5a8162f..2ff89a2 160000
--- a/submodule-path
+++ b/submodule-path
@@ -1 +1 @@
-Subproject commit 5a8162ff9a602deb96956854346988e1ee45672e
+Subproject commit 2ff89a2bfcaa014885a70b0da86e997ecd8d0688
Другой - это сам подмодуль: если вы cd submodule-path
и запустив различные команды Git, вы увидите, что это обычный Git-репозиторий. Единственное, что необычно в этом, это то, что он почти всегда находится в режиме «отсоединенного HEAD».
Ваш суперпроект Git, вероятно, имеет origin
. Это репозиторий, ну, технически, короткое имя, которое вы можете использовать в этом Git для , ссылается на другой репозиторий, который вы можете git push
зафиксировать, сделанный в суперпроекте. Вам потребуется сделать коммит в суперпроекте, а затем git push
этот новый коммит в origin
. Что именно входит в этот суперпроект коммит? Мы скоро увидим.
Ваш подмодуль Git также имеет origin
. Это другой другой репозиторий Git: четвертый Git на этой не очень хорошо прорисованной картине. Мне не ясно, хотите ли вы отправить коммиты в этот четвертый репозиторий. Возможно, вы do хотите получить коммит из этого хранилища. Есть несколько способов сделать это, включая использование git submodule update --remote
, возможно, с дополнительными опциями. Я предпочитаю просто cd submodule-path
и начать работать непосредственно в подмодуле Git , поскольку это сводит проблему к вещам, которые вы уже знаете, как делать: манипулировать одним локальным репозиторием Git на основе новых коммитов, которые появились в его origin
.
Предположим, вы просто хотите получить новые коммиты в подмодуле
Если это так, вы можете:
cd submodule-path # begin working in your submodule
git fetch # update origin/*
git checkout origin/master # get a detached HEAD on the desired commit
# (this assumes `origin/master` is the
# desired commit; it's impossible for me
# to know which commit you desire)
итеперь подмодуль имеет желаемый коммит в качестве отдельного заголовка. Отсюда git push
нечего: все коммиты, которые находятся в этом репозитории, являются коммитами, полученными из Git этого подмодуля origin
.
(Использование git submodule update --remote
может сделать cd submodue-path
и git fetch
и git checkout origin/master
для вас, все без изменения собственного рабочего каталога. Вся операция выполняется в своей собственной под-оболочке, так что ни одна из этих операций cd
не влияет на то, где вы находитесь. Это похоже на то, что ваш git submodule update --remote --merge
сделал: не было необходимости делать новый коммит слияния, поэтому он просто переключился на коммит, определенный по некоторому имени ветки в origin
.)
Но если вам нужно сделать новые коммиты в подмодуле .. .
В этом случае вы можете захотеть заставить субмодуль работать в ветке, чтобы вы работали в более нормальном рабочем процессе. Тогда вы, вероятно, захотите, например, git checkout master
, а затем выполнять различные команды. В конечном итоге вы можете получить новый коммит, сделанный в вашем хранилище субмодулей, который вам потребуется git push
в origin
репозиторий из субмодуля, чтобы другие люди могли получить этот коммиттоже.
Вы можете оставить подмодуль в его ветке. Ветвь подмодуля не имеет отношения к суперпроекту Git: суперпроект Git заботится только о том, какой commit извлечен в подмодуле. (Вот почему в более раннем случае, приведенном выше, мы можем просто переключить отсоединенную головку.)
НетЕсли субмодуль Git находится на правильном коммите, вы должны сделать новый коммит суперпроекта
. На этом этапе вы можете cd
вернуться из субмодуля в суперпроект. В git diff
вы увидите что-то в точности как вы цитировали выше, и git status
скажет:
modified: submodule-path (new commits)
Это не обязательно означает, что есть какие-то new фиксирует в хранилище подмодулей, которых нет в хранилище подмодулей origin
. Это просто означает, что репозиторий подмодулей включен (как его HEAD, отсоединен или нет) коммит, который не является коммитом, который текущий статус суперпроекта говорит, что должен быть включен.
Проблемаздесь то, что текущий коммит суперпроекта, в некотором смысле, неисправен. Это было правильно, но это больше не так, поскольку текущий коммит суперпроекта был бы дефектным, если бы вы, скажем, редактировали файл README.md
локально. Это означает, что вам нужно сделать в суперпроекте новый исправленный коммит. Суперпроект Git сделает новый коммит из того, что находится в индексе репозитория суперпроекта, так что теперь вам нужно обновить индекс.
Если вы изменили файл README.md
, то какобновить индекс:
git add README.md
Но то, что вы изменили, не было README.md
файлом. Вместо этого это был хеш-идентификатор субмодуля. Таким образом, вам нужно записать новый идентификатор хеша в индексе. Вот как вы это делаете:
git add submodule-path
Это берет хеш-идентификатор из подмодуля, выполнив cd submodule-path; git rev-parse HEAD
, чтобы получить необработанный хеш-идентификатор - тот, который появился в git diff
- и прочее, чтоID хеша в индекс. Теперь git diff
- который сравнивает индекс с вашим рабочим деревом - не будет отображать эти Subproject commit
строки больше, но git diff --cached
- который сравнивает текущую (суперпроектную) фиксацию с индексом - покажет . Теперь git status
скажет, что эти «новые коммиты» готовы к фиксации, а не «еще не подготовлены для фиксации».
Вы можете git add
любые другие файлы суперпроекта (если они есть)которые должны быть обновлены в индексе) в это время. Затем:
git commit
в суперпроекте создаст новый коммит, в котором будет записан хэш-идентификатор, который вы указали в индексе суперпроекта, когда вы запустили git add
в пути подмодуля.
You '(локально) мы выполнили обновление, но вот некоторые вещи, о которых стоит подумать
Обратите внимание, что каждый коммит в суперпроекте записывает хэш-идентификатор в подмодуле. Каждый раз, когда вы git checkout
делаете другой коммит суперпроекта, который не только извлекает правильные файлы суперпроекта в индекс (суперпроекта) и ваше (суперпроект) рабочее дерево, он также извлекает записанный хеш-идентификатор субмодуля в индекс (суперпроекта). не , по умолчанию, cd
в подмодуле и git checkout
этой конкретной фиксации по его хэш-идентификатору. Вы можете изменить это с помощью параметра или добавить --recursive
к git checkout
;или вы можете просто запустить git submodule update
, который сообщает вашему Git cd
в каждый подмодуль, по одному, и git checkout
идентификатор хеша, который в настоящее время записан в индексе (суперпроекта).
Вы будетев какой-то момент необходимо git push
новый коммит, который вы сделали в своем суперпроекте, до origin
(суперпроекта), чтобы новый коммит с его новым записанным идентификатором хеша появился в Git над origin
вашего суперпроекта. Вы можете делать это в любое время - но предположим, что вы сделали сделали новые коммиты в вашего подмодуля, и вы еще не использовали git push
в самом подмодуле для отправки этих новых коммитовorigin
субмодуля. В этом случае новый коммит, который вы сделали в суперпроекте, записывает хэш-идентификатор коммита, который существует только в вашем локальном хранилище субмодулей . Если кто-то запустит git fetch
для суперпроекта Git origin
, он получит этот новый хэш-идентификатор из нового отправленного вами коммита, но не сможет найти , который коммитит в их клон подмодуля. Так что, если вы сделали новые коммиты подмодулей, обычно лучше сначала git push
их, , а затем git push
новый суперпроект коммитов.
(Если выне делал никаких новых подмодульных коммитов, здесь нет проблем.)