Об ИТ из Канады

Блог Михаила Флёнова - программист, блогер, автор нескольких скандальных книг какими-то глазами...
git - современное управление кодом - Статья : блог Михаила Флёнова

git - современное управление кодом

Сегодня читал статью о git и там было написано немного неверное представление о команде checkout. Автор не совсем понимает идеологию git, поэтому допустил несколько досадных ошибок в описании. Статья и автор не имеют значения, потому что я не собираюсь обсуждать его и его работу. Но я решил написать эту статью о git со своей точки зрения и опыта работы.  

Итак, самое главное и отличие git состоит в том, что для внесения изменения в код не нужно блокировать файл. Вы делаете изменения и система просто запоминает именно изменения. Потом, когда код сливается с другим кодом, изменения накладываются на основной код.  

Все начинается с инициализации нового репозитория для вашего кода - git init. Этим вы создаете ствол дерева вашего проекта, который будет называться master. Никогда не разрабатывайте новый код прямо стволе, это очень и очень плохая практика. У нас master установлен на сервере staging от которого мы запускаем код на рабочие сервера. Клиент на этом сервере может делать изменения в параметрах, которые хранятся в конфигурационных файлах и программисты могут пофиксить на этом сервере мега срочные баги, но только в очень редких случаях.  

Ветки кода 

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

У нас разработка идет командами, но даже при единоличной разработке все деревья создаются на удаленном сервере. Программисты клонируют к себе на локальный компьютер удаленный репозиторий (git clone) и работают локально, отправляя изменения на сервер. 

Работа программиста начинается с того, что он забирает последние изменения с сервера к себе - git fetch. Теперь, когда нужно начать работу над новым кодом или фиксом, создается новая ветка от основного дерева: 

git checkout -b fixdone/345321 origin/master 

git checkout вытаскивает данные из репозитория. Ключик -b говорит, что нужно не просто вытащить, а создать новую ветку с именем fixdone/345321. Именование веток у каждого свое, кто-то предпочитает давать осмысленные имена, а у нас чаще всего это done, fixdone, newdone или figznaetchtodone (это магическое слово каждый выбирает сам) плюс номер тикета через слешь.  

После этого через пробел идет по документации необязательный параметр - от какой ветки вы хотите создать свою. Я рекомендую всегда указывать этот параметр. В примере выше я указал origin/master - удаленный главный ствол нашего дерева.  

Еще немного об именовании. Почему origin/master - это удаленный ствол? На это указывает слово origin. Мы создали новую ветку fixdone/345321 и это локальная копия на нашем диске. Удаленная копия в репозитории будет иметь имя origin/fixdone/345321. Мы создаем свою ветку именно от удаленного дерева, которое где-то на сервере. Просто у вас локально тоже может быть свой собственный master и его можно создать так: 

git checkout -b master origin/master 

Эта команда создает локальных копию текущего мастера. Теперь проходит месяц, вы делаете git fetch, чтобы вытащить все изменения, сделанные другими программистами и эта команда обновлены на вашем диске все удаленные ветки ствол. То есть origin/master обновится, но созданный вами локальный master обновляться не будет. И если в следующий раз вы создадите новую ветку от локальных копии: 

git checkout -b fixdone/333445 master 

То она будет создана от вашего не обновленного master и будет содержать более старый код. 

Двигаемся дальше. Если не указать явно от какой ветки создается ваша новая ветка, то она будет создана от текущей. Это может привести к проблемам. Допустим, вы создали новую ветку: 

git checkout -b fixdone/111 origin/master 

Написали код, который нужно будет поместить на рабочий сервер первого января и потом создали еще одну ветку: 

git checkout -b fixdone/222  

Эта ветка будет создана от fixdone/111 и будет содержать все изменения в этой ветке. Вы пишите новый код, который нужно отправить на рабочий сервер уж завтра. Результат - когда вы отправите в продакшин fixdone/222 вместе с ним уйдет и код 111, который не должен быть там. 

Чтобы случайно не попасть в такую ситуацию, всегда явно указывайте главную ветку и в большинстве случаев это будет origin/master. 

Надеюсь хотя бы поверхностно смысл того, что я описываю понятен, потому что слишком много таких непонятных вещей, особенно для тех, кто даже с svn  не работал. Но чуть позже все должно быт более понятно, зачем мы создаем ветки и как будем это использовать.  

Сохранение кода 

Итак, мы создали новую ветку от основного дерева. Не нужно блокировать какие-то файлы от изменения другими пользователями, просто изменяете любой код или добавляете новый без оглядки на других программистов в вашей команде. Когда вы закончили работу над кодом, то данные нужно сохранить в своей ветке. Еще раз подчеркиваю, именно в своей и ни в коем случае не в мастер. 

Выполните команду git status, чтобы посмотреть какие файлы изменены и какая ветка кода является текущей.  

Желательно так же выполнить команду git diff, которая покажет, какие строчки изменились. Система git построена так, что она сохраняет только изменения. Если вы изменил только одну строчку, а git diff показывает, что у вас изменен весь файл, то ваш редактор кода переформатировал код. Возможно вы являетесь любителем форматирования кода проблеми и настроили редактор на замену символов tab пробелами.  

Ни в коем случае не сохраняете в репозитории файлы, которые непроизвольно изменены во всех строках, иначе вас потом ждет серьезный разговор с другими программистами, потому что такой комит проще удалить, чем использовать. 

Еще возможен вариант, что у вас настроено автоматического исправление конца строки между nix/windows. Кстати, git тут глючит и эту функцию лучше отключить. В скрытой директории .git есть gitconfig файл, в котором нужно добавить строку autocrlf = off (если мне не изменяет память, но тут может изменять).  

Если вы убедились, что git diff показывает подсвеченным только реально измененные строки, их можно добавлять в комит.  

Добавляются файлы так: 

git add имяфайла 

Вместо имени файла можно использовать и маски. Если нужно добавить все измененные то можно использовать ключик -u 

git add -u 

Эта команда добавит все измененные файлы. Если вы создавали новые модули, то для них все же придется выполнять git add отдельно.  

Теперь, когда вы добавили все изменения, можно подтверждать их командой  

git commit -m 'это мой первый проект' 

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

Итак все сохранено и изменения можно отправлять на сервер для этого используется команда push: 

git push origin fixdone/345321 

Вот тут есть небольшой конфуз для новичков. Видя слово origin начинаешь думать об удаленной ветке, о которой мы говорили ранее. Но это отдельно стоящее слово и в данном контексте у него другое значение - после него указывают какую ветку вы хотите отправить в репозиторий.  

После выполнения этой команды на сервере появляется удаленная ветка origin/fixdone/345321, которую другие программиста могу забрать к себе на компьютер git fetch и использовать.  

Смешивание кода 

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

git checkout -b tests/qa1 origin/master 

Теперь имея свою копию мастера, он начинает трестировать различные тикеты. Допустим, что к нему пришел тикет 345321 с вашим кодом. Он должен наложить ваш код на свою ветку: 

git merge origin/fixdone/345321 

Так как у тестера локально нет кода вашей ветки, у него есть копия удаленной, он указывает именно origin/fixdone/345321.  

Теперь ваши изменения наложены на код тестера, он может их трестировать и посылать программистами клеймы с наездами.  

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

git checkout -b golive20121129 origin/master 

Теперь на эту новую ветку натягиваем все изменения, которые должны уйти в продакшин: 

git merge origin/fixdone/345321 

git merge origin/fixdone/345322 

git merge origin/fixdone/345323 

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

Запускаются юнит тесты и идет ручное тестирования всех изменений в одной большой кучке. Когда тесты заканчиваются, код отправляется в репозиторий: 

git push origin golive20121129 

Теперь на staging сервере, где текущим всегда выбран мастер выполняет следующие команды: 

git fetch 

git merge origin/golive20121129 --no-commit --no-ff 

Первая команда забирает последние изменения с сервере, а вторая сливает ветку golive20121129 с мастером. И снова тестирование. 

Откат кода 

Обратите внимание, что на staging сервере мы при выполнены команды merge использовали два ключика 

--no-commit - по умолчанию git после выполнения команды merge тут же выполняет commit. В принципе, ничего плохого тут нет, но если что-то пойдет не так, то без commit проще откатить изменения.  

--no-ff - оставляет указатель на точку мастера на том же месте. Это отдельная история о внутренностях git и возможно я напишу чуть позже advanced версию по git. 

Допустим, что запуск прошел неудачно и нужно откатить все изменения. Для этого выполняем следующую команду 

git reset --hard 

Все не закомиченые изменения будут отменены и убраны из текущей ветки кода.  

Что если нужно отменить только один файл? Его можно вытащить из мастера, для этого выполняем команду: 

git checkout имяфайла 

Текущие изменения на файл будут отменены.  

После того, как все оттестировано в основной ветке staging сервера, изменения можно сохранить.  

В чем сила брат?

А сила в том, что не нужно блокировать файлы. Вы просто создаете отдельные ветки кода, пишите свой код, а git сохраняет у себя только ваши изменения. Он хранит, что пользователь 1 изменил в файле XXX строку 10, 20 и 30 и какие изменения были сделаны. Когда вы выполняете команду merge, то git как бы пишет поверх ветки, в которую вы мёржите все то, что находиться у него в комите. 

У меня на работе был проект два года назад, который я выполнил и закомитил. Он пролежал в загажнике пол года, прежде чем клиент решился запустить его в продакшен. Я не знаю, как современный svn, но в старом такое было невозможно. Помню как в Source Safe приходилось издеваться с блокированием файла и нельзя был разрабатывать код на будущее. Все писалось прямо в одной мусорке кода. 

Чуть позже займусь за написание более про двинутой версии статьи.  


Внимание!!! Если ты копируешь эту статью себе на сайт, то оставляй ссылку непосредственно на эту страницу. Спасибо за понимание

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Внимание!

А ты уже читал мою последнюю книгу о больших сайтах и приложениях? Узнай, что это такое здесь

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповидания на русском или английском языке.

Пишите мне