Из архива Linux16.net: Git: с ветки на ветку

(Опубликовано Mabel aka Yababay, 2009-05-05)

Продолжаю осваивать git и делиться своими маленькими открытиями. На этот раз речь пойдет о таком удобстве, как branch (ветвь). Всем, кто пользовался системами контроля версий, это понятие знакомо. Ветвь представляет собой отдельную линию развития разрабатываемого ПО, на которой можно поэкспериментировать без ущерба для основного процесса разработки. Ведь мы работаем для заказчика, который, как правило, эксперименты оплачивать не склонен. Но и без «метода проб и ошибок» мало кто обходится. Git — прекрасное решение в этой ситуации.

Когда мы инициализируем репозитарий git в каталоге с каким-нибудь проектом, в нем автоматически создается ветка master, с которой в принципе можно работать ни о чем больше не задумываясь. Файлы и каталоги постепенно добавляются в репозитарий командами типа

git add <filename>
git commit -a -m "bla-bla-bla"


С временем распухшее хозяйство начинает раздражать. Допустим, программист находит способ сделать всё изящнее и обойтись меньшим количеством файлов и каталогов, причем даже имена их будут в ряде случаев другими. Самое время создать новую ветку:

git branch superpuperlight


где superpuperlight — любое слово латинскими буквами, отражающее суть ветки. Переключение с ветки на ветки производится командой

git checkout master


или

git checkout superpuperlight


Чтобы посмотреть, как это всё работает, попробуйте в какой-нибудь пробной директории выполнить:

git init
echo "Yooooooooooooooooooooooooooooooo!" > test.txt
git add .
git commit -a -m "First commit in master branch"
git branch shortYo
git checkout shortYo
echo "Yo!" > test.txt
git add .
git commit -a -m "First commit in shortYo branch"


Теперь попереключайтесь между ветками с помощью команды git checkout <имя ветки> и понаблюдайте за содержимым файла test.txt. Удобство налицо.

Но есть одна особенность, которую нужно учитывать, особенно тем, кто переходит на git с других систем контроля версий, таких как svn. В svn и ей подобных понятие checkout означает «привести состояние локального репозитария в соответствие с центральным». Например, вы повредили или удалили у себя в каталоге с проектом несколько файлов. Команда svn checkout восстановит их, скопировав из удаленного репозитария. Команда git checkout ведет себя иначе: она пометит отсутствующие файлы на удаление и при ближайшем коммите реально уберет их из репозитория (хотя сделать откат и восстановить такие файлы будет, конечно же, можно). Git имеет дело не с централизованным репозитарием, как svn, а с локальным, тем самым, что лежит в скрытой директории .git в текущем каталоге проекта. Именно в нее делаются коммиты и из нее делаются чекауты.

Как же быть, если в разных ветках проекта структура файлов и каталогов различаются? Если мы изобрели изящное решение програмистской задачи и хотим его девелопить в отдельной ветке, неужели нам так и придется лицезреть громоздкую структуру файлов и каталогов, родившуюся в результате «ошибок молодости»? Я так и не нашел научного ответа на этот вопрос, но изобрел «антинаучный», который меня пока вполне устраивает.

1. Делаем коммит старого, громоздкого варианта проекта;
2. Тупо с помощью команды mv перемещаем его файлы и каталоги в какую-нибудь временную директорию (чтобы потом копировать некоторые готовые решения в свежую ветку). в каталоге проекта должна остаться только директория .git;
3. Создаем новую ветку в репозитарии (git branch <имя новой ветки>) и переключаемся на нее (git checkout <имя новой ветки>);
4. Создаем в вычищенной дректории проекта необходимые каталоги и файлы (что-то копируем, что-то пишем заново);
5. Добавляем (git add ...) и коммитим (git commit… ) их до тех пор, пока файлы не будут работать как надо.

Допустим, что поэкспериментировав с новой веткой и придя к выводу «Ну и дурак же я был!» мы хотим вернуться к старому, тяжеловесному, но зато адекватно работающему варианту, который оставили в ветке master. Как избежать мешанины из файлов, принадлежащих разным веткам? Мой «антинаучный» метод для этого случая выглядит следующим образом:

1. Делаем последний коммит экспериментальной ветки.
2. Удаляем (можно перемещением во временную директорию) содержимое каталога проекта (кроме директории .git).
3. Переключаемся на ветку master (git branch master);
4. Выполняем git checkout, но добавляя конкретный список файлов, который нужно восстановить из репозитария. Понятное дело, что вручную это сделать немыслимо, поэтому поручаем формирование такого списка оболочке bash:

git checkout `git ls-files`


Команда git checkout, как сказано выше, работает не совсем понятным для бывшего пользователя svn образом. А вот если после нее перечислить конкретные файлы, то делает именно то, что нужно: восстанавливает их из репозитария. Такой подход позволяет восстановить ветку master точно в том состоянии, в каком мы ее оставили на момент начала экспериментов.

Что-то мне подсказывает, что есть более элегантное решение этой задачи и если этот материал прочитает человек, хорошо ориентирующийся в git, прошу такового поделиться опытом.
  • +3
  • 02 февраля 2010, 18:02
  • yababay

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.