Здесь произошло то, что ваш суперпроект теперь несовместим. В частности, в вашем суперпроекте есть gitlinks, которые необходимо зафиксировать.
Вы должны добавить новые gitlinks (с git add
, как обычно) и зафиксировать (как обычно). Затем вы можете нажать новый коммит (как обычно).
Подмодуль подразумевает суперпроект
Подмодуль — это просто репозиторий Git, который напрямую используется другим репозиторием Git. Сам подмодуль в данном случае является обычным репозиторием Git: он ничего не знает об этом другом репозитории Git. Другой репозиторий — это тот, который мы называем суперпроектом, и он действительно знает о подмодуле.
Любому репозиторию Git нужен каталог .git
с некоторыми данными.
Как правило, репозиторий Git создается путем его клонирования из другого места:
git clone http://...
или что-то еще. Или вы можете запустить git init
в каталоге. В любом случае вы получите каталог .git
, в котором находится сам репозиторий Git. В этом .git
вы обычно определяете пульт с именем origin
. Это короткое имя (в частности, имя origin
!), которое записывает URL-адрес, который вы указали для git clone
выше. Этот URL-адрес может даже указывать на ваш собственный репозиторий, скажем, на GitHub.
(Если вы начали с чужого репозитория, а затем решили создать свой собственный на GitHub, у вас может быть даже два пульта. Обычно вы должны назвать свой собственный репозиторий origin
, а другой — upstream
, но насколько Сам Git обеспокоен, это просто произвольные имена.Единственная причина, по которой мы все согласны с origin
, заключается в том, что это имя git clone
создает для нас, когда мы впервые запускаем git clone url
.)
В любом случае данные в каталоге .git
включают следующее:
- URL-адрес для
origin
.
- Имена любых ветвей и идентификаторы хэшей коммитов, которые идентифицируют эти ветки.
- Точно так же имена тегов и их коммитов.
- текущая фиксация: что именно извлечено в репозитории? Это может быть имя ветки, и в этом случае репозиторий находится в ветке, или это может быть необработанный хэш-идентификатор фиксации, и в этом случае репозиторий находится в "отключенном" состоянии. ГОЛОВА».
Что, если суперпроект создает подмодуль?
Суперпроект должен знать несколько вещей о каждом из своих подмодулей. Во-первых, в суперпроекте есть файл с именем .gitmodules
. Внутри этого .gitmodules
файла вы найдете URL для каждого подмодуля. Вы также найдете путь для каждого подмодуля.
Точная форма и содержание этого файла описаны в документации gitmodules. а>. Чтобы процитировать его немного, предположим, что он говорит:
[submodule "libfoo"]
path = include/foo
url = git://foo.com/git/lib.git
Это означает, что когда вы клонируете суперпроект, а затем запускаете git submodule init
, ваш Git будет знать, что он должен запустить git clone git://foo.com/git/lib.git
— это часть url — с клоном, идущим в каталог include/foo
: путь< /em> часть.
В этой головоломке отсутствует один важный элемент. После того, как ваш Git клонирует другой Git в include/foo
, какая фиксация проверяется в подмодуле?
В большинстве обычных репозиториев это не такой уж большой вопрос. Какой коммит проверяется? Я не знаю, я просто запускаю git checkout master
, верно? Это дает мне последний коммит в ветке master
, чего я и хочу.
Суперпроекты и подмодули так не работают. Когда я использую подмодуль из своего суперпроекта, я строю свой код суперпроекта вокруг одного конкретного коммита в подмодуле. Например, я мог зависеть конкретно от v3.4.1
чьей-то еще библиотеки, поэтому я спускался в подпроект и запускал git checkout v3.4.1
, чтобы проверить этот конкретный тег.
В идеале я мог бы записать этот тег в своем суперпроекте (это было бы неплохо, и gitlinks должны разрешать это, но в настоящее время они этого не делают).1 Но тег, в Git — это просто удобочитаемое имя для одного конкретного коммита. Тег v3.4.1
может быть именем фиксации feeddadac0ffee...
или чем-то подобным. Это — большой уродливый хэш-идентификатор — это то, что на самом деле входит в gitlink.
Сам gitlink хранится в каждом коммите, точно так же, как обычный файл хранится в каждом коммите. Если я делаю новый коммит в суперпроекте с новым или измененным файлом README
, новая версия README
попадает в репозиторий Git, а новый коммит ссылается на новый README
. Каждая фиксация после этого продолжает ссылаться на новый README
.
То же самое верно и для gitlink: если мой include/foo
относится к хэш-идентификатору для v3.4.1
подмодуля, каждый коммит с этого момента имеет запись gitlink, которая гласит: «когда вы проверяете этот коммит, вы также должны войти в субмодуль include/foo
и проверить хэш-идентификатор feeddadac0ffee...
".
1Если кто-то хочет попробовать добавить это, я думаю, что есть способ сделать это, который может быть даже несколько обратно совместим: сохранить необработанный хэш-идентификатор, как обычно, за которым следует байт NUL, а затем по ссылочному имени. Старый Git, который не понимает новый тип gitlink, может напрямую использовать хэш-идентификатор, а более новый Git может обнаружить и использовать имя. Записи Gitlink в любом случае потребуют аналогичного изменения при переходе хэша от SHA-1 к тому, что Git будет использовать в будущем, поэтому сейчас самое время добавить это.
Что если владелец подмодуля сделает новый релиз?
Итак, я протестировал свой суперпроект с v3.4.1
, и все работает. Большой! Но теперь тот, кто отвечает за эту include/foo
библиотеку, обновил свой код и выпустил версию v3.4.2
. Эта новая версия имеет некоторые новые функции, и я хотел бы использовать их.
Я, как владелец суперпроекта, должен теперь зайти в свой подмодуль и git fetch
, а затем git checkout v3.4.2
. (Возможно, это не feeddadac0ffee
, а хэш-идентификатор deadcabbadcab005e...
.) Затем я должен вернуться к своему суперпроекту, внести все изменения, необходимые для использования нового подмодуля, все протестировать и зафиксировать.
Когда я делаю новую фиксацию для использования v3.4.2
подмодуля, я должен не только фиксировать мои изменения. Мне также нужно обновить мою gitlink. Поскольку я уже сделал git checkout deadcabbadcab005e
— или git checkout v3.4.2
, что на самом деле то же самое, — в подмодуле, все, что мне нужно сделать, это git add include/foo
в моем суперпроекте. Это добавляет обновленную gitlink в мой индекс, так что когда я запускаю git commit
, я записываю новую gitlink вместе с другими моими изменениями.
Это создает новую фиксацию, и теперь я могу отправить свою фиксацию, если есть какое-то другое место, где я также храню свой суперпроект (на GitHub или где-то еще).
person
torek
schedule
01.07.2017