22.03.2016 Git: проект и его сателлиты

Материал из SRNS
Перейти к: навигация, поиск
 
Строка 270: Строка 270:
 
</source>
 
</source>
  
[[Категория::Git]]
+
[[Категория: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.

git clone /tmp/test_git/remote/myproject
cd myproject

Добавить сюда подпроект можно так:

git submodule add /tmp/test_git/remote/sub1
git submodule add /tmp/test_git/remote/sub2

При этом git создаст папки sub1 и sub2 и склонирует туда соответствующие проекты.

Важно что? В основном проекте myproject будет создан файл .gitmodules, содержащий список подроектов. Git будет понимать, что всё, что лежит в папках sub1 и sub2, не следует рассматривать, как кучу файлов. Они будут рассматриваться, как единые объекты sub1 и sub2 с соответствующими хэшами.

Что мы увидим в результате?

git status

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. При этом подпроекты автоматически не обновяться, но будет сообщение, что в рабочем каталоге что-то не то:

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:   sub2 (new commits)

На самом деле в sub2 файлы не изменились. Просто проект myproj ссылается на более новые их версии, каталог sub2 надо обновить. Это можно сделать так:

git submodule update

git status
On branch master
Your branch is up-to-date with 'origin/master'.

nothing to commit, working directory clean

Загляем в sub2:

cd 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. Ну, можно решить данный вопрос одним из многочисленных способов. Например, так:

git checkount master

ВАЖНО! Тут я понимал, что master у меня указывает на тот же коммит.

Допустим, master устарел, а правильный коммит лежит в origin/master, что будет ЧАСТО:

git status

HEAD detached at c036200
nothing to commit, working directory clean

gitk --all

20160322 OldSub2Master.png

«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 checkout master
git merge origin/master

После этого всё стало так, как надо:

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

20160322 NewSub2Master.png

[править] Вывод

  • Когда мы обновляем проект, git проверяет версии подпроектов и говорит о несоответствиях.
  • Когда мы делаем "git submodule update", git приводит все подпроекты к тому состоянию, которое нужно основному проекту.

Таким образом, после "git pull origin" в основном проекте всё будет, как надо для основного проекта.

Но что, если в подпроектах будут более новые коммиты, чем в основном проекте? Git их проигнорирует - мы попадём в detached HEAD с нужным нам состоянием.

А если мы хотим обновить подпроект? Можно зайти в него и сделать обычный "git pull origin", он обновиться. Но после этого обновления потребует уже проект myproj, т.к. пока он ссылается на старое состояние подпроекта:

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)

Теперь sub1 обновлён, надо обновить myproj

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

[править] Проблема с песочницей (грозное предупреждение!)

Мы привыкли уже в Git лёгким движением руки создавать новую ветку и делать там всё, что угодно. В принципе, при работе с подпроектами тоже будет так.

НО! В каждом из подпроектов ветка изменяется отдельно. Допустим, мы сменили в myproj ветку на bug1. При этом в подпроектах sub1 и sub2 осталась ветка master. Если при этом делать изменения в sub1 и sub2, они уйдут в соответствующие удалённые хранилища уже не из песочницы bug1, и из ветки master.

Другие ветки основного проекта myproj при этом будут ссылаться на нужные им хэши и ничего не сломается... до тех пор, пока в другой ветке кто-то не решит обновить подкаталоги sub1 и sub2 до master и получит при этом изменения, которые были сделаны в процессе работы над песочницей bug1.

Об этом надо помнить. И если хочется проботать действительно с песочницей, создавать ветки и в подпроектах, которые будут изменяться. А можно и во всех подпроектах.

git submodule foreach "git checkout -b bug1"

Радикальное средство, однако.

[править] Рецепты

[править] Хочу добавить подмодуль

cd myporj
git submodule add <URL>

[править] Хочу обновить вообще все так, чтобы правильно собирался основной проект

cd myproj
git pull origin
git submodule update

[править] Хочу понять, последние ли версии подмодулей используются в основном проекте

cd myproj
git submodule update
git submodule status

 60b25bee1f8906545d58805ed0cde3c336a5a877 sub1 (remotes/origin/HEAD)
 c0362002f9adbfc501b4febb9ab4c26547e8a3c5 sub2 (heads/master)

Вот здесь sub2 указывает на ветку master, значит всё хорошо. А вот sub1 указывает на remotes/origin/HEAD. Это означает, что локальный master устарел, а в удалённой ветке есть более новая версия, он использует её оттуда. Надо вручную обновить ветку master до актуальной.

[править] Хочу просто обновить все подпроекты до последних доступных версий

cd myproj
git submodule foreach 'git checkout master; git pull origin'

Тут предполагается, что во всех рабочих каталогах ветка master. Если там должна быть другая ветка, придётся менять её вручную.

Ну, и после данной операции нужно обновить основной проект, т.к., вероятно, он ссылается на более старые версии подпроектов.

[править] Хочу создать такую песочницу ... всем песочницам песочницу

(Шепотом)

cd myproj
git checkout -b bug1
git submodule foreach "git checkout -b bug1"

[ Хронологический вид ]Комментарии

(нет элементов)

Войдите, чтобы комментировать.

Персональные инструменты
Пространства имён

Варианты
Действия
SRNS Wiki
Рабочие журналы
Приватный файлсервер
QNAP Сервер
Инструменты