Git для начинающих. Урок 4.
Коммиты и история коммитов
Работа с файлами
Видеоурок. Часть 1. Практика, основы работы с коммитами и историей коммитов
Видеоурок. Часть 2. Практика, дополнительные приемы и фишки
Видеоурок. Часть 3. Общие наблюдения и советы. Как делать «хорошие» коммиты
Конспект урока
Краткое содержание урока, основные инструкции для командной строки, полезные ссылки и советы.
Что такое коммит
По-научному это сохранение состояния, фиксация или слепок изменений.
Как сделать коммит
Представим, что мы добавляем блок учеников на сайт. Добавляем новую разметку в index.html и новые стили в main.css. Чтобы сохранить изменения, нужно их закоммитить. Но предварительно сообщить git, какие именно файлы мы хотим положить в коммит. Команда git add добавляет (или подготавливает) файлы к коммиту. Можно добавить файлы по отдельности, вот так
Добавлять все файлы сразу удобно, но стоит всегда внимательно проверять, точно ли мы хотим добавить в коммит все измененные файлы. Если ошиблись и какой-то файл добавлять в коммит не нужно, то можно исключить этот файл из подготовленных.
Создаем сам коммит
Состояние файлов в git. Измененные и подготовленные файлы
Подготовленные файлы отличаются от измененных тем, что они «подготовлены» к коммиту, то есть будут добавлены в следующий коммит.
git add filename добавляет или подготавливает файл к коммиту.
git reset filename удаляет файл из подготовленных к коммиту.
Содержимое файлов при этом не меняется. Один файл может одновременно находиться и в измененных, и в подготовленных. Это происходит, если мы добавили файл, но не закоммитили и продолжили делать в нем измения.
Из чего состоит коммит
Каждый коммит имеет
Как добавить файлы и сделать коммит одной командой
Отслеживаемые и неотслеживаемые файлы
История коммитов, git log
Все коммиты можно посмотреть в истории коммитов. История хранит все данные обо всех коммитах проекта. Показывается история командой
История включает в себя все сведения о коммитах: хэш, автор, дата и список изменений. Список изменений смотреть командой git show по хэшу коммита
Если мы сделали коммит, но хотим поправить его commit message
Эта команда перезапишет сообщение последнего коммита. Это перезаписывание истории, операция опасная. Лучше делать ее только до того, как отправили коммит на сервер (push разберем через урок)
Откат коммитов, git revert
Если мы сделали неверный коммит и хотим откатить изменения, сделанные в нем, то поможет команда git revert
Работа с файлами
При работе с файлами нужно учесть, что новые файлы git отправляет в неотслеживаемые. Поэтому при добавлении нового файла стоит сначала его закоммитить, а потом вносить изменения, чтобы они были доступны через git diff
При обычном переименовании файла в файловом менеджере или командой mv git сначала показывает 2 файла: старый удаленный и новый неотслеживаемый. Чтобы git понял, что этот файл именно переименованный, нужно сначала добавить эти файлы в подготовленные к коммиту
Тогда при команде git status файл будет отображаться именно как переименованный
Можно избежать этого промежуточного состояния, если переименовать файл в командной строке таким образом
Тогда файл будет сразу отображаться, как переименованный. То же самое с удалением файла
Командная строка vs IDE
Работа в PhpStorm продемонстрирована в первых двух частях видео.
Как и в прошлом уроке мы видим, что некоторые вещи удобнее делать в IDE. Например, процесс добавления файлов (git add) в PhpStorm при создании коммита почти не привлекает внимания. Но важно понимать, что такое git add и зачем он нужен. И что любая IDE под капотом все равно выполняет базовые команды git. Просто для нас предоставляется удобная обертка, чтобы мы больше сосредоточились на самом проекте, а не на git.
Наблюдения и советы при работе с коммитами
В каждой команде свои правила и соглашения. Но я приведу общие советы и размышления, которые помогут в любом проекте
Используйте удобные инструменты в IDE, но не забывайте командную строку. В ней вы лучше будете понимать, как устроен git, как он работает
Хорошие и плохие коммиты
С точки зрения git коммиты не бывают плохими и хорошими. Но есть удачные и неудачные подписи к коммитам с точки зрения наших коллег. Несколько примеров
Добавлен файл VipClient
Работа с vip-клиентами вынесена в отдельный класс
По первому коммиту можно предположить, что в VipClient мы скорее всего работаем с ВИПами. Во втором коммите это точно понятно, плюс дополнительная информация, что это отдельный класс.
Поправлены стили в main.css
Рефакторинг стилей в main.css
Первый коммит говорит о правке стилей, но непоянтно, что именно поправлено. Бага? Новые значения? Изменен цвет текста по рекомендации дизайнера? Второй коммит ясно указывает, что это рефакторинг
Маленький фикс
Исправлена опечатка в заголовке title страницы «О компании»
Коммит «маленький фикс» даже приблизительно не говорит, в чем он заключается. Второй коммит дает полное представление
Немного о философии коммитов
Концепция коммитов заставляет если не менять подход к разработке, то по-другому к ней относиться. С git нам приходится не просто писать код, а планировать его написание. Планировать задачи, над которыми мы работаем. Декомпозировать задачи, то есть разбивать их на небольшие части.
Мы больше думаем о том, что мы работаем не одни, а в команде. История коммитов общая для всего проекта. Чем лучше мы научимся формировать и подписывать коммиты, тем легче будет ориентироваться в истории нам самим и нашим коллегам.
В любом проекте важны не только код и его структура, но и история коммитов и хорошие commit message.
На этом все. В следующем уроке мы будем больше работать с историей коммитов и посмотрим различные варианты использования команды git log
Основы Git
Git очень удобная система контроля версий, которая сейчас используется практические повсеместно. Она нужна для того, чтобы команды могли кооперироваться в создании программного продукта и совмещать код написанный разными людьми в одном репозитории.
Когда я учил Git мне говорили, что в работе мне понадобятся всего 3 команды:
Правда, по сути мне немного слукавили, нужен был ещё как минимум:
Однако, на этом все мои теоретические знания по Git заканчивались и достаточно долгое время я пользовался только этими командами, покуда в один момент не начал работать над веб-приложениями, над которыми со мной работали ещё несколько человек.
Там мне объяснили какие команды также нужны в разработке, зачем они используются и как часто они используются. Сегодня я решил поделиться этими командами с вами.
Основная терминология
Работа с Git
Прежде всего нам понадобятся команды для работы с файлами. Знать add конечно хорошо, но нужно иногда и удалять что-то из кэшируемых файлов или изменять поведение Git для определенных файлов. Сегодня я разберу некоторые команды, которые позволят вам манипулировать с файлами, ветками, коммитами в Git.
init
Данная команда инициализирует систему контроля версий. Для того чтобы создать новый репозиторий достаточно просто ввести:
clone
Данная команда нужна для того, чтобы клонировать репозиторий из облака. Можно клонировать репозитории из Github, Gitlab, BitBucket и других сервисов. Для того чтобы склонировать репозиторий нужно ввести:
Данная команда понадобится вам, когда вам нужно добавить файл для кэширования. Давайте разберёмся как это работает:
Вы изменяете файлы, можете изменять достаточно много файлов, задачи изменения которых вообще никак не связаны
Вы решаете «закоммитить» ваши файлы (сделать сохранение версии, для того чтобы Git запомнил все ваши изменения в файлах и как-то назвал их, для этого есть отдельная команда git commit )
Вы также можете добавить файлы, которые ранее не отслеживались, для того чтобы Git занёс их в свою систему хранения версий и вы могли откатываться на какую-то из версий файла
Проделав данный алгоритм, состоящий из двух команд вы занесёте все файлы из вашего проекта в систему контроля версий Git.
Но, что если вам не хочется вносить все файлы? Тогда вы может использовать следующий синтаксис:
Также мы можем сделать так, чтобы Git искал некоторые названия в дочерних директориях и игнорировал их:
Данная команда поможет, когда нам нужно избавиться от файла, она подобно команде rm удаляет файл из файловой системы и кэша Git, позволяя нам быстро избавиться от файла.
Данный пример удалит файл file.txt из кэша и файловой системы.
Но, что если мы добавили файл, который нам более не нужен в кэше, но нужен в файловой системе? Тогда мы можем воспользоваться следующей командой:
Данная команда удалит файл из «кэша», но что это значит? Допустим, что мы «закоммитили» (сохранили версию, об этом поговорим вот уже совсем скоро) наш файл, а теперь хотим, чтобы Git считал что мы его удалили, а сами просто оставили его на диске. Для этого и нужна команда выше. Она просто говорит Git: «Слушай, а давай ты просто удалишь этот файл из кэша и не будешь его показывать в репозитории, а я оставлю копию у себя на ПК, ок?»
Таким образом мы можем работать с данным файлом и Git не будет знать что именно в нём мы изменяем, а затем просто можем опять добавить его. Файл будет висеть в состоянии «untracked» (не отслеживается) до тех пор, покуда мы его опять не добавим.
commit
Думаю, что стоит поговорить об этом уже сейчас, ибо позже без данной команды уже никуда. Данная команда буквально сохраняет версию, в которой указывается что именно в файлах мы изменили.
Обычно разработчики сохраняют версию программы с помощью данной команды:
В данном случае мы просто скажем, чтобы Git сохранил все изменения, которые мы сделали в файлах, которые отслеживаются. Файлы, которые не отслеживаются просто не попадают в версию, а также их изменения никак нельзя отследить.
Для того чтобы отменить последний коммит (отменить не изменения, а именно просто разкоммитить изменения) и совместить его с текущими изменениями используйте команду:
show
Данная команда нужна для того, чтобы быстро показать что было сделано за предыдущие коммит:
Выведутся изменения следующим образом:
status
До этого момента мы могли только посмотреть что творилось в предыдущем коммите, однако с помощью git log мы можем посмотреть историю наших коммитов:
Если же вы хотите красиво вывести все ваши коммиты в столбик, то используйте данную команду:
В данной команде мы описываем что хотим просматривать коммиты и их названия в одну строку, хотим чтобы коммиты сокращали свой ID, а также чтобы всё это красиво было разбито по списку
diff
С помощью данной команды мы можем посмотреть на изменения между коммитами. Эта комманда является одной из самых мощных в Git, вам стоит обратить на неё внимание:
Так называемые «ID-коммита» можно взять и вышеприведенной git log
Если вы хотите посмотреть историю изменений в файлах в определенном коммите, то используйте следующую команду:
Если вы хотите посмотреть на изменения только тех файлов, которые добавлены для отслеживания, то нужно ввести следующую команду:
branch
В Git есть ветки для разделения версий. Если коммит нужен для того, чтобы сделать snapshot (слепок изменений) файлов, то ветки нужны для того, чтобы эти snapshot’ы разделять. У вас может быть ветка
любое другое название
Для того чтобы перечислить все ветки с помощью Git нужно ввести следующую команду:
Для того чтобы создать новую ветку нужно ввести:
checkout
Checkout используют для того, чтобы переходить между ветками. Для того чтобы перейти на другую ветку достаточно просто написать:
Для того чтобы создать ветку и сразу же перейти на неё достаточно ввести:
merge
Соединение веток не являются сложной темой. Для того чтобы слить текущую ветку с другой нужно ввести:
push
В завершение
Здесь мы чуть более глубже познакомились с основами Git, поняли как работать с ветками, как их мерджить, как коммитить файлы, смотреть изменения, а также как показывать последние коммиты.
Если вы хотите больше узнать о веб-разработке, а также о линуксе, то милости прошу в мой блог на телеграм.
Надеюсь данная статья помогла вам чуть лучше узнать Git. Хорошего дня и продуктивной недели!
Git на практике
Существует замечательная книга Pro Git, в которой подробно описаны все команды и возможности гита. Но после ее прочтения у многих остается непонимание того, как это все использовать на практике. В частности, у программистов разного уровня часто возникают вопросы о том, как работать с ветками в Git, когда их заводить и как мержить между собой. Порой мне попадались очень «оригинальные» и неоправданно усложненные схемы работы с гитом. В то время как в сообществе программистов уже сформировалась схема работы с гитом и ветками в нем. В этой статье я хочу дать краткий обзор основных моментов при работе с Git, и описать «классическую» схему работы с ветками. Многое из того что описано в этой статье будет справедливо и для других систем управления версиями.
Эта статья может быть полезна для программистов, которые только начинают осваивать Git, или какую-то другую систему управления версиями. Для опытных программистов эта статья покажется очень простой и банальной.
Для начала давайте разберемся с тем что такое ветка и коммит.
Коммит
Можно сказать, что коммит это основной объект в любой системе управления версиями. В нем содержится описание тех изменений, которые вносит пользователь в код приложения. В Git коммит состоит из нескольких так называемых объектов. Для простоты понимания можно считать, что коммиты это односвязный список, состоящий из объектов в которых содержаться измененные файлы, и ссылка на предыдущий коммит.
У коммита есть и другие свойства. Например, дата коммита, автор, комментарий к коммиту и т.п.
В качестве комментария обычно указывают те изменения, которые вносит этот коммит в код, или название задачи которую он решает.
Git это распределенная система управления версиями. Это значит, что у каждого участника проекта есть своя копия репозитория, которая находиться в папке “.git”, которая расположена в корне проекта. Именно в этой папке хранятся все коммиты и другие объекты Git. Когда вы работаете с Git, он в свою очередь работает с этой папкой.
Завести новый репозиторий очень просто, это делается командой
Таким образом у вас получиться новый пустой репозиторий. Если вы хотите присоединиться к разработке уже имеющегося проекта, то вам нужно будет скопировать этот репозиторий в свою локальную папку с удаленного репозитория. Делается это так:
Существует несколько основных областей в которых находиться код.
При этом можно использовать маски со звездочкой.
Потом вы делаете коммит в свой локальный репозиторий
git commit –m “Комментарий к коммиту”
Когда коммитов накопиться достаточно много, чтобы ими можно было поделиться, вы выполняете команду
После чего ваши коммиты уходят в удаленный репозиторий.
Если нужно получить изменения из удаленного репозитория, то нужно выполнить команду
После этого, в вашем локальном репозитории появятся те изменения, которые были отправлены другими программистами.
Код в рабочей области проекта образуется применением тех изменений, которые содержаться в коммитах. У каждого коммита есть свое имя, которое представляет собой результат хеш функции sha-1 от содержимого самого коммита.
Просмотреть коммиты можно при помощи команды
Формат ответа этой команды по дефолту не очень удобен. Вот такая команда выведет ответ в более читаемом виде
Что бы закончить просмотр нужно нажать на клавишу q
Посмотреть, что находиться в рабочей директории и staging area можно командой
Рабочую директорию можно переключить на предыдущее состояние выполнив команду
Только перед тем как это делать выполните git status и убедитесь, что у вас нет никаких локальных и не зафиксированных изменений. Иначе Git не поймет, как ему переключаться. git status подскажет вам что можно сделать с локальными изменениями что бы можно было переключиться. Этого правила следует придерживаться и при всяких других переключениях рабочей области.
Ветка
Ветка в Git это подвижный указатель на один из коммитов. Обычно ветка указывает на последний коммит в цепочке коммитов. Ветка берет свое начало от какого-то одного коммита. Визуально это можно представить вот так.
Сделать новую ветку и переключиться на нее можно выполнив команды
git pull
git checkout –b
Просто сделать ветку, не переключаясь на нее можно командой
переключиться на ветку
Важно понимать, что ветка берет свое начало не от ветки, а от последнего коммита который находиться в той ветке, в которой вы находились.
Ветка обычно заканчивается специальным merge коммитом, который говорит, что ветку нужно объединить с какой-то другой веткой. В merge коммите содержатся две ссылки на два коммита которые объединяются в одну ветку.
Существует другая ситуация при объединении веток, в которой merge может произойти без merge commit. Дело в том, что если в одной из веток не произошло никаких изменений, то необходимость в merge commit с двумя предками отпадает. В таком случае, при слиянии веток, Git просто сделает пометку о том, что дальше будут идти коммиты той ветки с которой эта ветка была объединена. Такая схема merge называется слияние-перемотка (fast-forward merge), визуально это можно представить вот так.
Во всех этих случаях, после того, как ветка объединяется с другой веткой, все коммиты сделанные в ней, попадают в ветку с которой она была объединена. Так же важно понимать, что merge это не двунаправленная операция. Если смержить ветку задачи в мастер ветку, то в мастер ветке появится код, который находился в ветке задачи, а в ветке задачи не появиться новый код из мастер ветки. Если нужно что бы это произошло, нужно смержить мастер ветку в ветку задачи.
Что бы смержить одну ветку в другую нужно вначале переключиться на ту ветку, в которую вы хотите смержить
Потом получить последние изменения сделанные в этой ветке выполнив
Затем выполнить команду
Так выглядит работа с ветками в общих чертах.
Популярные схемы работы с ветками в Git
Теперь можно описать популярные схемы работы с ветками в гите.
Ветки нужны для того, чтобы программисты могли вести совместную работу над проектом и не мешать друг другу при этом. При создании проекта, Git создает базовую ветку. Она называется master веткой. Она считается центральной веткой, т.е. в ней содержится основной код приложения.
Классическая схема работы с ветками
Обычно перед тем как взяться за решение какой-то задачи, программист заводит новую ветку от последнего рабочего коммита мастер ветки и решает задачу в этой новой ветке. В ходе решения он делает ряд коммитов, после этого тестирует код непосредственно в ветке задачи. А после того как задача решена, делают merge обратно в мастер ветку. Такую схему работы часто используют с юнит тестами и автоматизированным деплоем. Если юнит тесты будут покрывать весь код, то можно настроить деплой так, что вначале будут прогоняться все тесты в ветке задачи. А после этого, если они прошли успешно, будет происходить merge и деплой. При такой схеме можно добиться полной автоматизации при тестировании и деплои.
Именная ветка
Неопытные программисты заводят себе именную ветку и работают всегда в ней. Они решают по одной задачи за раз, и когда заканчивают решение одной из задач, делают новый Pull запрос через Web интерфейсе (об этом чуть ниже). Недостаток этого подхода в том, что так можно решать только одну задачу и нельзя быстро переключиться на решение другой задачи. Еще один недостаток в том, что ветки так со временем будут все сильнее расходиться и код в ветке программиста рано или поздно устареет относительно мастер ветки и его придется обновить. Для этого можно либо смержить мастер ветку в ветку программиста, либо завести новую ветку для этого программиста от последнего рабочего состояния в мастер ветке. Правда к тому времени, как это произойдет программист уже может освоить гит в достаточной мере что бы перейти на “классическую” схему работы. Таким образом эта схема имеет место быть для неопытных пользователей Git.
Схема с dev веткой
Другая схема очень похожа на классическую, только в ней помимо мастер ветки есть еще девелоперская ветка, которая деплоится на тестовый сервер. Такую ветку обычно называют dev. Схема работы при этом такая. Программист перед выполнением новой задачи заводит для нее ветку от последнего рабочего состояния в мастер ветке. Когда он заканчивает работу над задачей, то мержит ветку задачи в dev ветку самостоятельно. После этого, совместными усилиями задача тестируется на тестовом сервере вместе с остальными задачами. Если есть ошибки, то задачу дорабатывают в той же ветке и повторно мержат с dev веткой. Когда тестирование задачи заканчивается, то ВЕТКУ ЗАДАЧИ мержат с мастер веткой. Важно заметить, что в этой схеме работы с мастер веткой нужно мержить ветку задачи, а не dev ветку. Ведь в dev ветке будут содержаться изменения, сделанные не только в этой задаче, но и в других и не все эти изменения могут оказаться рабочими. Мастер ветка и dev ветка со временем будут расходиться, поэтому при такой схеме работы периодически заводят новую dev ветку от последнего рабочего состояния мастер ветки. Недостатком этого подхода является избыточность, по сравнению с классической схемой. Такую схему работы с ветками часто используют если в проекте нет автоматизированных тестов и все тестирование происходит вручную на сервере разработки.
Так же следует отметить что эти схемы работы можно комбинировать между собой, если в этом есть какая-то необходимость.
Pull запросы
С этим понятием имеется путаница. Дело в том, что в Git есть две совершенно разные вещи, которые можно назвать Pull запросом. Одна из них, это консольная команда git pull. Другая это кнопка в web интерфейсе репозитория. На github.com она выглядит вот так
Про эту кнопку и пойдет речь дальше.
Если программист достаточно опытный и ответственный, то он обычно сам сливает свой код в мастер ветку. В противном случае программист делает так называемый Pull запрос. Pull запрос это по сути дела запрос на разрешение сделать merge. Pull запрос можно сделать из web интерфейса Git, или при помощи команды git request-pull. После того как Pull запрос создан, остальные участники могут увидеть это, просмотреть тот код который программист предлагает внести в проект, и либо одобрить этот код либо нет. Merge через pull запросы имеет свои плюсы и минусы. Минус в том, что для тесной команды опытных программистов такой подход будет лишним. Это будет только тормозить работу и вносить в нее оттенки бюрократии.
С другой стороны, если в проекте есть не опытные программисты, которые могут сломать код, то Pull запросы могут помочь избежать ошибок, и быстрее обучить этих программистов наблюдая за тем какие изменения они предлагают внести в код.
Так же Pull запросы подходят для широкого сообщества программистов, работающих с открытым исходным кодом. В этом случае нельзя заранее сказать что-то о компетенции таких разработчиков и о том, что они хотят изменить в коде.
Конфликты
Конфликты возникают при мердже веток если в этих ветках одна и та же строка кода была изменена по-разному. Тогда получается, что Git не может сам решить какое из изменений нужно применить и он предлагает вручную решить эту ситуацию. Это замедляет работу с кодом в проекте. Избежать этого можно разными методами. Например, можно распределять задачи так, чтобы связанные задачи не выполнялись одновременно различными программистами.
Другой способ избежать этого, это договориться о каком-то конкретном стиле кода. Тогда программисты не будут менять форматирование кода и вероятность того, что они изменят одну и ту же строчку станет ниже.
Еще один хороший совет, который поможет вам избежать конфликтов при работе в команде, это вносить минимум изменений в код при решении задач. Чем меньше строчек вы поменяли, тем меньше вероятность что вы измените ту же самую строку что и другой программист в другой задаче.
После того, как в мастер ветке достигается состояние, которое можно считать стабильным оно отмечается тегом с версией этого состояния. Это и есть то что называют версией программы.
Делается это вот так
Что бы передать ветки в удаленный репозиторий нужно выполнить команду
Теги удобны еще и тем, что можно легко переключиться на то состояние кода которое отмечено тегом. Делается это с помощью все той же команды
Различные системы деплоя и автоматизированной сборки используют теги для идентификации того состояния, которое нужно задеплоить или собрать. Так сделано потому, что если мы будем собирать или деплоить код последней версии, то есть риск, что какой-то другой программист в этот момент внесет какие-то изменения в мастер ветку, и мы соберем не то что хотели. К тому же так будет проще переключаться между рабочими и проверенными состояниями проектов.
Если вы будете придерживаться этих правил и “классической” схемы работы с ветками, то вам будет проще интегрировать ваш Git с другими системами. Например, с системой непрерывной интеграции или с репозиторием пакетов, таким как packagist.org. Обычно сторонние решения и всякие расширения рассчитаны именно на такую схему работы с гитом, и если вы сразу начнете делать все правильно, то это может стать большим плюсом для вас в дальнейшем.
Это обзор основных моментов при работе с Git. Если вы хотите узнать про Git больше, то я вам посоветую прочитать книгу Pro Git. Вот здесь.
В этой статье была приведена упрощенная схема представления коммитов. Но перед тем как ее написать я решил разобраться как именно хранятся коммиты на диске. Если вас тоже заинтересует этот вопрос, то вы можете прочитать об этом вот здесь.