22.03.2016 Git: проект и его сателлиты
Boldenkov (обсуждение | вклад) (→Обновление подпроектов) |
Boldenkov (обсуждение | вклад) |
||
(не показаны 16 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
<summary [ hidden ] > | <summary [ hidden ] > | ||
− | https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Solar_System_size_to_scale_ru.svg/500px-Solar_System_size_to_scale_ru.svg.png | + | <center>https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Solar_System_size_to_scale_ru.svg/500px-Solar_System_size_to_scale_ru.svg.png</center> |
Как быть с подпроектами в Git | Как быть с подпроектами в Git | ||
</summary> | </summary> | ||
+ | {{TOCright}} | ||
Задача: включить внутрь проекта другой проект. | Задача: включить внутрь проекта другой проект. | ||
Строка 100: | Строка 101: | ||
[[File:20160322_OldSub2Master.png|400px]] | [[File:20160322_OldSub2Master.png|400px]] | ||
+ | «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 до нужного коммита: | ||
+ | <source lang="bash"> | ||
+ | git checkout master | ||
+ | git merge origin/master | ||
+ | </source> | ||
+ | |||
+ | После этого всё стало так, как надо: | ||
+ | <source lang="bash"> | ||
+ | git status | ||
+ | |||
+ | 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 | ||
+ | </source> | ||
+ | |||
+ | [[File:20160322_NewSub2Master.png|400px]] | ||
+ | |||
+ | == Вывод == | ||
+ | |||
+ | * Когда мы обновляем проект, git проверяет версии подпроектов и говорит о несоответствиях. | ||
+ | * Когда мы делаем "git submodule update", git приводит все подпроекты к тому состоянию, которое нужно основному проекту. | ||
+ | |||
+ | Таким образом, после "git pull origin" в основном проекте всё будет, как надо для основного проекта. | ||
+ | |||
+ | Но что, если в подпроектах будут более новые коммиты, чем в основном проекте? Git их проигнорирует - мы попадём в detached HEAD с нужным нам состоянием. | ||
+ | |||
+ | А если мы хотим обновить подпроект? Можно зайти в него и сделать обычный "git pull origin", он обновиться. Но после этого обновления потребует уже проект myproj, т.к. пока он ссылается на старое состояние подпроекта: | ||
+ | |||
+ | <source lang="bash"> | ||
+ | cd 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) | ||
+ | </source> | ||
+ | |||
+ | Теперь sub1 обновлён, надо обновить myproj | ||
+ | |||
+ | <source lang="bash"> | ||
+ | git add sub1 | ||
+ | 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 | ||
+ | </source> | ||
+ | |||
+ | == Проблема с песочницей (грозное предупреждение!) == | ||
+ | |||
+ | Мы привыкли уже в Git лёгким движением руки создавать новую ветку и делать там всё, что угодно. В принципе, при работе с подпроектами тоже будет так. | ||
+ | |||
+ | НО! В каждом из подпроектов ветка изменяется отдельно. Допустим, мы сменили в myproj ветку на bug1. При этом в подпроектах sub1 и sub2 осталась ветка master. Если при этом делать изменения в sub1 и sub2, они уйдут в соответствующие удалённые хранилища уже не из песочницы bug1, и из ветки master. | ||
+ | |||
+ | Другие ветки основного проекта myproj при этом будут ссылаться на нужные им хэши и ничего не сломается... до тех пор, пока в другой ветке кто-то не решит обновить подкаталоги sub1 и sub2 до master и получит при этом изменения, которые были сделаны в процессе работы над песочницей bug1. | ||
+ | |||
+ | Об этом надо помнить. И если хочется проботать действительно с песочницей, создавать ветки и в подпроектах, которые будут изменяться. А можно и во всех подпроектах. | ||
+ | |||
+ | <source lang="bash"> | ||
+ | git submodule foreach "git checkout -b bug1" | ||
+ | </source> | ||
+ | |||
+ | Радикальное средство, однако. | ||
+ | |||
+ | == Рецепты == | ||
+ | |||
+ | === Хочу добавить подмодуль === | ||
+ | |||
+ | <source lang="bash"> | ||
+ | cd myporj | ||
+ | git submodule add <URL> | ||
+ | </source> | ||
+ | |||
+ | === Хочу обновить вообще все так, чтобы правильно собирался основной проект === | ||
+ | |||
+ | <source lang="bash"> | ||
+ | cd myproj | ||
+ | git pull origin | ||
+ | git submodule update | ||
+ | </source> | ||
+ | |||
+ | === Хочу понять, последние ли версии подмодулей используются в основном проекте === | ||
+ | |||
+ | <source lang="bash"> | ||
+ | cd myproj | ||
+ | git submodule update | ||
+ | git submodule status | ||
+ | |||
+ | 60b25bee1f8906545d58805ed0cde3c336a5a877 sub1 (remotes/origin/HEAD) | ||
+ | c0362002f9adbfc501b4febb9ab4c26547e8a3c5 sub2 (heads/master) | ||
+ | </source> | ||
+ | |||
+ | Вот здесь sub2 указывает на ветку master, значит всё хорошо. А вот sub1 указывает на remotes/origin/HEAD. Это означает, что локальный master устарел, а в удалённой ветке есть более новая версия, он использует её оттуда. Надо вручную обновить ветку master до актуальной. | ||
+ | |||
+ | === Хочу просто обновить все подпроекты до последних доступных версий === | ||
+ | |||
+ | <source lang="bash"> | ||
+ | cd myproj | ||
+ | git submodule foreach 'git checkout master; git pull origin' | ||
+ | </source> | ||
+ | |||
+ | Тут предполагается, что во всех рабочих каталогах ветка master. Если там должна быть другая ветка, придётся менять её вручную. | ||
+ | |||
+ | Ну, и после данной операции нужно обновить основной проект, т.к., вероятно, он ссылается на более старые версии подпроектов. | ||
+ | |||
+ | === Хочу создать такую песочницу ... всем песочницам песочницу === | ||
+ | |||
+ | (Шепотом) | ||
+ | |||
+ | <source lang="bash"> | ||
+ | cd myproj | ||
+ | git checkout -b bug1 | ||
+ | git submodule foreach "git checkout -b bug1" | ||
+ | </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"
[ Хронологический вид ]Комментарии
Войдите, чтобы комментировать.