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

Материал из SRNS
Перейти к: навигация, поиск

Содержание

Задача: включить внутрь проекта другой проект.

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 Сервер
Инструменты