22.03.2016 Git: проект и его сателлиты
Boldenkov (обсуждение | вклад) |
Boldenkov (обсуждение | вклад) |
||
Строка 270: | Строка 270: | ||
</source> | </source> | ||
− | [[Категория | + | [[Категория:Git]] |
{{wl-publish: 2016-03-22 12:50:40 +0300 | Boldenkov }} | {{wl-publish: 2016-03-22 12:50:40 +0300 | Boldenkov }} |
Текущая версия на 13:59, 1 апреля 2016
Задача: включить внутрь проекта другой проект.
Git позволяет делать это! Смотрите подмодули.
[править] Создание подмодулей
Допустим, у нас есть проект mypoject.
cd myproject
Добавить сюда подпроект можно так:
git submodule add /tmp/test_git/remote/sub2
При этом git создаст папки sub1 и sub2 и склонирует туда соответствующие проекты.
Важно что? В основном проекте myproject будет создан файл .gitmodules, содержащий список подроектов. Git будет понимать, что всё, что лежит в папках sub1 и sub2, не следует рассматривать, как кучу файлов. Они будут рассматриваться, как единые объекты sub1 и sub2 с соответствующими хэшами.
Что мы увидим в результате?
On branch master
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitmodules
new file: sub1
new file: sub2
Мы видим здесь 3 объекта - sub1, sub2 и .gitmodules.
Именно так и будут интерпретироваться подпроекты - как объекты с хэшем. Соответственно, когда мы коммитим из проекта myproj его текущее состояние, сохраняется хэш каждого из подпроекта.
[править] Обновление подпроектов
Допустим, мы обновили проект myproj. При этом подпроекты автоматически не обновяться, но будет сообщение, что в рабочем каталоге что-то не то:
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: sub2 (new commits)
На самом деле в sub2 файлы не изменились. Просто проект myproj ссылается на более новые их версии, каталог sub2 надо обновить. Это можно сделать так:
git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
Загляем в sub2:
git status
HEAD detached at c036200
nothing to commit, working directory clean
Почему detached HEAD? В каталоге myproj было указано, что подпроект sub2 должен указывать на коммит с определённым хэшем. Этот хэш найден в удалённой ветке подпроекта sub2, и туда он сделал "git checkout" во время операции "git submodule update". Локальная ветка master не была обновлена и устарела. Более того, даже ветка master указывает на коммит c036200, то хранилище всё равно попадёт в "detached HEAD". HEAD указывает на c036200, master указыват на c036200, просто HEAD не указыват на master. Ну, можно решить данный вопрос одним из многочисленных способов. Например, так:
ВАЖНО! Тут я понимал, что master у меня указывает на тот же коммит.
Допустим, master устарел, а правильный коммит лежит в origin/master, что будет ЧАСТО:
HEAD detached at c036200
nothing to commit, working directory clean
gitk --all
«WTF?» — подумаете вы. А ведь всё нормально! В проекте myproj указано, что sub2 имеет хэш c0362. При этом текущий master на диске указывает на два коммита назад и имеет хэш 10ed. Что делает "git submodule update"? Выкачивает удалённую ветку origin/master в каталоге sub2, и делает "git checkout c0362". Так как текущее состояние sub2 - master, указывающий на 10ed, то мы получаем detached HEAD - HEAD указыват на с0362 и не указыват ни на какую ветку. При этом origin/master тоже указыват на нужный коммит - но на это git submodule не смотрит. При этом origin/master может указывать на ещё более новый коммит - имеет право.
Что делать? Можно обновить master до нужного коммита:
git merge origin/master
После этого всё стало так, как надо:
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
cd ..
git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
[править] Вывод
- Когда мы обновляем проект, git проверяет версии подпроектов и говорит о несоответствиях.
- Когда мы делаем "git submodule update", git приводит все подпроекты к тому состоянию, которое нужно основному проекту.
Таким образом, после "git pull origin" в основном проекте всё будет, как надо для основного проекта.
Но что, если в подпроектах будут более новые коммиты, чем в основном проекте? Git их проигнорирует - мы попадём в detached HEAD с нужным нам состоянием.
А если мы хотим обновить подпроект? Можно зайти в него и сделать обычный "git pull origin", он обновиться. Но после этого обновления потребует уже проект myproj, т.к. пока он ссылается на старое состояние подпроекта:
git status
On branch master
Your branch is up-to-date with 'origin/master'
cd sub1
git fetch
remote: Counting objects: 2, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (2/2), done.
From /tmp/test_git/remote/sub1
f2ca542..60b25be master -> origin/master
git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
git merge origin master
Updating f2ca542..60b25be
Fast-forward
sub1_c3.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 sub1_c3.txt
cd ..
git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: sub1 (new commits)
Теперь sub1 обновлён, надо обновить myproj
git commit -m "sub1 updated in myproj"
[master a8e2ddb] sub1 updated in myporj
1 file changed, 1 insertion(+), 1 deletion(-)
git push origin
Counting objects: 2, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 251 bytes | 0 bytes/s, done.
Total 2 (delta 1), reused 0 (delta 0)
To /tmp/test_git/remote/myproj/
4c30f5f..a8e2ddb master -> master
[править] Проблема с песочницей (грозное предупреждение!)
Мы привыкли уже в Git лёгким движением руки создавать новую ветку и делать там всё, что угодно. В принципе, при работе с подпроектами тоже будет так.
НО! В каждом из подпроектов ветка изменяется отдельно. Допустим, мы сменили в myproj ветку на bug1. При этом в подпроектах sub1 и sub2 осталась ветка master. Если при этом делать изменения в sub1 и sub2, они уйдут в соответствующие удалённые хранилища уже не из песочницы bug1, и из ветки master.
Другие ветки основного проекта myproj при этом будут ссылаться на нужные им хэши и ничего не сломается... до тех пор, пока в другой ветке кто-то не решит обновить подкаталоги sub1 и sub2 до master и получит при этом изменения, которые были сделаны в процессе работы над песочницей bug1.
Об этом надо помнить. И если хочется проботать действительно с песочницей, создавать ветки и в подпроектах, которые будут изменяться. А можно и во всех подпроектах.
Радикальное средство, однако.
[править] Рецепты
[править] Хочу добавить подмодуль
git submodule add <URL>
[править] Хочу обновить вообще все так, чтобы правильно собирался основной проект
git pull origin
git submodule update
[править] Хочу понять, последние ли версии подмодулей используются в основном проекте
git submodule update
git submodule status
60b25bee1f8906545d58805ed0cde3c336a5a877 sub1 (remotes/origin/HEAD)
c0362002f9adbfc501b4febb9ab4c26547e8a3c5 sub2 (heads/master)
Вот здесь sub2 указывает на ветку master, значит всё хорошо. А вот sub1 указывает на remotes/origin/HEAD. Это означает, что локальный master устарел, а в удалённой ветке есть более новая версия, он использует её оттуда. Надо вручную обновить ветку master до актуальной.
[править] Хочу просто обновить все подпроекты до последних доступных версий
git submodule foreach 'git checkout master; git pull origin'
Тут предполагается, что во всех рабочих каталогах ветка master. Если там должна быть другая ветка, придётся менять её вручную.
Ну, и после данной операции нужно обновить основной проект, т.к., вероятно, он ссылается на более старые версии подпроектов.
[править] Хочу создать такую песочницу ... всем песочницам песочницу
(Шепотом)
git checkout -b bug1
git submodule foreach "git checkout -b bug1"
[ Хронологический вид ]Комментарии
Войдите, чтобы комментировать.