Что такое коммит в программировании
Git commit
Коммит в Git и коммит в SVN
Порядок действий
Снимки состояния, а не различия
Помимо различий между SVN и Git с практической точки зрения, их базовая реализация также основывается на совершенно разных концепциях проектирования. SVN отслеживает различия в файле, тогда как модель управления версиями Git базируется на снимках состояния. Например, в коммите SVN содержатся различия исходного файла и файла, добавленного в хранилище. А Git записывает в каждом коммите все содержимое каждого файла.
Такой подход позволяет выполнять многие операции в Git намного быстрее, чем в SVN, поскольку конкретную версию файла не нужно «собирать» из его различий — во внутренней базе данных Git находится уже готовая редакция каждого файла.
Модель снимков состояния Git влияет практически на все аспекты модели управления версиями, от инструментов ветвления и слияния до рабочих процессов при совместной работе.
Распространенные опции
Коммит проиндексированного состояния кода. Эта команда откроет текстовый редактор с предложением ввести комментарий к коммиту. После ввода комментария сохраните файл и закройте текстовый редактор, чтобы выполнить коммит.
Выполнение коммита состояния со всеми изменениями в рабочем каталоге. Эта команда включает только изменения отслеживаемых файлов (тех, которые были в какой-то момент добавлены в историю с помощью команды git add ).
Этот параметр добавляет команде commit новый уровень функциональности. При передаче этого параметра будет изменен последний коммит. Вместо создания нового коммита проиндексированные изменения будут добавлены в предыдущий коммит. Кроме того, эта команда откроет настроенный текстовый редактор системы с предложением изменить указанный ранее комментарий к коммиту.
Примеры
Сохранение изменений с помощью команды commit
Окрашенный зеленым цветом вывод «new file: hello.py » сообщает о том, что файл hello.py будет сохранен при выполнении следующего коммита. Коммит выполняется с помощью указанной ниже команды.
Эта команда откроет текстовый редактор (настраиваемый через git config ) для ввода комментария к коммиту и покажет список файлов, которые будут зафиксированы в этом коммите:
Особых требований для комментариев к коммиту в Git нет, но обычно первая строка содержит описания коммита длиной до 50 символов, затем следует пустая строка и детальное пояснение того, что было изменено. Пример:
Обычно первая строка комментария к коммиту аналогична теме электронного письма. Остальная часть комментария считается телом сообщения и используется для детального описания набора изменений в коммите. Многие разработчики предпочитают использовать в комментариях настоящее время. Так комментарий становится больше похож на список действий в репозитории, благодаря чему многие операции перезаписи истории становятся более интуитивно понятными.
Обновление коммита (параметр amend)
Продолжим работу с файлом hello.py из приведенного выше примера. Давайте внесем в файл hello.py новые изменения и запустим следующие команды:
Снова откроется настроенный текстовый редактор. Но на этот раз он будет содержать комментарий к коммиту, который мы уже вводили ранее. Это указывает на то, что мы не создаем новый коммит, а редактируем последний.
Резюме
Модели коммитов в SVN и в Git существенно отличаются, но из-за общей терминологии часто возникает путаница. Если вы начинаете работу в Git, имея опыт работы с SVN, вам будет полезно знать, что коммиты в Git — простая операция, которую следует выполнять часто. В SVN коммит — сложная операция, связанная с выполнением удаленного запроса, тогда как в Git коммиты выполняются локально и по более эффективному алгоритму.
Готовы изучить Git?
Ознакомьтесь с этим интерактивным обучающим руководством.
Что такое коммит в программировании
Руководство по написанию коммитов
Это руководство поможет понять, почему важно писать хорошие сообщения коммитов и как это делать.
Также это руководство может помочь прояснить, что такое коммит, почему важно писать хорошие сообщения, узнать лучшие практики и советы по созданию и (пере)написанию истории коммитов.
Простыми словами, коммит — это снимок ваших локальных файлов, записанный в локальный репозиторий. Вопреки распространённому мнению, git хранит не только изменения между файлами, но и в целом полную версию всех файлов. Для файлов, которые не менялись от одного коммита к другому, git хранит только ссылку на предыдущий идентичный файл, который уже был сохранен.
На изображении ниже показано, как git хранит данные с течением времени. Каждая «версия» является коммитом:
Почему сообщения коммитов важны?
Чтобы добиться максимального результата, мы можем использовать некоторые полезные практики и стандарты, описанные в следующем разделе.
Это некоторые практики, собранные из моего опыта, статей и других руководств. Если у вас есть предложение (или вы не согласны с некоторым) не стесняйтесь открыть пулреквест и внести свой вклад.
Используйте повелительное наклонение
Но зачем использовать повелительное наклонение?
Сообщение коммита описывает, что конкретно делают зафиксированные изменения, его конечный результат, а не что было сделано.
В замечательной статье Криса Бимса (Chris Beams) (перевод на русский) приводится шаблон предложения, который может использоваться, чтобы лучше писать сообщения коммитов в императивной форме:
Начинайте сообщение коммита с заглавной буквы
Смысл этой рекомендации простой: в соответствии с правилами грамматики первое слово предложения начинается с заглавной буквы.
Использование этой практики может варьироваться от человека к человеку, от команды к команде или даже от языка к языку. Заглавная или нет, важно придерживаться единого стандарта и следовать ему.
Старайтесь описывать изменения так, чтобы указывать на исходный код
Это полезно во многих случаях (пр. несколько коммитов, различные изменения и рефакторинг), чтобы помочь проверяющим понять о чём думал автор коммита.
Используйте тело сообщения для объяснения «почему», «для чего», «как» и дополнительные детали
Тема и описание сообщения разделены пустой строкой.
Дополнительные пустые строки считаются частью описания.
Избегайте общих сообщений или сообщений без какого-либо контекста
Ограничьте длину строк
Рекомендуется использовать максимум 50 символов для темы и 72 символа для описания.
Сохраняйте согласованность языка
Для владельцев проектов: Выберите язык и пишите все сообщения коммитов используя этот язык. В идеале, он должен совпадать с комментариями в коде, стандартным переводом (для переведенных проектов), и т.д.
Для участников проекта: Пишите сообщения коммитов на том языке, который используется в истории коммитов.
Перебазировка vs. Слияние
Этот раздел является кратким пересказом превосходного руководства «Merging vs. Rebasing» от Atlassian.
Кратко: Применяет ваши коммиты в ветке, один за другим, к базовой ветки (например, master), генерируя новое дерево.
Кратко: Создаёт новый коммит, называемый (соответственно) коммит слияния (merge commit), с различиями между двумя ветками.
Почему некоторые люди предпочитают перебазирование вместо слияния?
Я, в частности, предпочитаю перебазирование вместо слияния. По следующим причинам:
Когда нужно делать объединение коммитов?
Объединение (Squashing) — это процесс объединения множества коммитов в один-единственный коммит.
Это может пригодиться в ряде ситуаций, например:
Когда избегать перебазирования или сжатия?
Избегайте этого в публичных коммитах или в общих ветках, в которых работают несколько человек. Перебазирование и слияние также перезаписывает историю коммитов и существующие коммиты, делая это с коммитами, которые находятся в разных ветках (например, коммиты, отправленные в удаленный репозиторий или коммиты из других веток) могут вызвать путаницу и поэтому можно потерять изменения (как локальные, так и удаленные) из-за различающегося дерева и конфликтов.
Полезные команды git
Используйте их, чтобы объединить коммиты, изменить сообщения, переписать/удалить/изменить порядок коммитов и т.д.
Используйте эту команду, чтобы привести в порядок коммиты, не прибегая к перебазированию. В этой статье есть хорошие примеры того, как и когда это делать.
Эта команда может быть очень полезной для применения коммита, который был сделан в неверной ветке, чтобы не писать код заново.
Давайте представим, что у нас есть следующий список различий:
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 поддерживает быстрое разделение и слияние версий, включает инструменты для визуализации и навигации по нелинейной истории разработки.
Ничего не понятно, давай еще раз
Какие такие версии?
Версия — это состояние файла (или нескольких файлов) в какой-то конкретный момент времени. Например, пустой файл (1), тот же файл с каким-то текстом (2) и этот же файл, в котором была исправлена опечатка (3) — три разные версии одного файла, которые были получены последовательной модификацией (изменением) файла.
Системы чего.
Система управления версиями — программа, позволяющая сохранять состояние файлов (те самые версии), возвращаться к ранее сохраненному состоянию, сохранять последовательность изменений внесенных в файлы, отменять или заново применять эти изменения, отслеживать авторство изменений.
Что там с этими версиями делают?
Разделение версий — независимые изменения одного файла.
Версионность на примере текстового файла
Например, у нас есть файл с каким-то текстом (версия этого файла). Файл отправляется на проверку, там обнаруживается и исправляется опечатка (получаем новую версию файла). Независимо от этого в старый (неисправленный) файл дописывается еще что-то (получаем еще одну версию этого файла). Т.е., на данный момент у нас есть два разных файла (две версии одного файла), которые были независимо друг от друга созданы на основе одной общей версии.
Слияние версий — объединение двух и более независимых версий. Для примера выше, слиянием будет объединение двух существующих версий нашего файла в одну — файл, в котором будет и новый текст, и исправленная опечатка.
А при чем тут история?
История разработки — совокупность всех версий файлов, над которыми ведется работа. Историей разработки в данном случае будет список изменений:
добавление изначального текста
добавление нового текста
объединение двух версий файла (при выполнении слияния)
Нелинейная история — история, в которой изменения вносятся не одно за другим последовательно, а может быть внесено несколько независимых изменений на основе одной версии файла (исправление опечатки и добавление нового текста). Т.е. мы создаем две параллельные истории изменений файла.
Немного терминологии
Репозиторий (repository) — совокупность файлов, состояние которых отслеживается, и история их изменений. По факту, репозиторий — это проект, над которым ведется работа, и все изменения в этом проекте. Для отслеживания состояния файла его необходимо добавить в репозиторий.
Коммит (commit) — сохраненное состояние (версия) файлов репозитория.
Ветка (branch) — последовательность коммитов (история изменения состояния репозитория). Каждый коммит в ветке имеет «родителя» (parent commit) — коммит, на основе которого был получен текущий. В репозитории может быть несколько веток (в случаях, когда к одной версии репозитория применяется несколько независимых изменений).
HEAD — указатель на текущий коммит (указатель на состояние, в котором репозиторий находится на данный момент).
Мастер (master, main) — основная ветка репозитория, создается автоматически при создании репозитория.
Мердж (слияние, merge) — объединение двух или более веток. В процессе мерджа изменения с указанной ветки переносятся (копируются) в текущую.
Целевая ветка мерджа — ветка, изменения с которой объединяются с текущей веткой.
База слияния (merge base) — последний общий коммит двух веток.
Мердж коммит (merge commit) — коммит, который создается автоматически по завершению процесса слияния веток. Мердж коммит содержит в себе все изменения целевой ветки мерджа, которые отсутствуют в текущей (все коммиты целевой ветки, которые начиная с базы слияния, но не включая её).
Слияние перемоткой (fast-forward merge) — слияние веток, при котором в текущей ветке отсутствуют новые коммиты (последний коммит текущей ветки является базой слияния). При таком мердже текущая ветка просто переходит в состояние целевой ветки (указатель HEAD переносится на последний коммит целевой ветки). Мердж коммит при этом не создается.
Слияние без перемотки (non fast-forward merge) — слияние, при котором новые коммиты (относительно базы слияния) присутствуют как в текущей, так и в целевой ветках.
В пустом репозитории, в основной ветке, создаем пустой файл, добавляем в репозиторий (теперь git будет отслеживать состояние файла) и коммитим (коммит А).
Добавляем в файл текст, коммитим еще раз (коммит B).
Создаем новую ветку (как бы копируя состояние репозитория), вносим изменения в файл и снова коммитим (коммит С).
Возвращаемся на предыдущую ветку (теперь репозиторий находится в состоянии, которое сохранилось при коммите B, без изменений, которые вносились в новой ветке).
Вносим новые изменения, создаем новый коммит (D).
История изменений при создании новой ветки
После этого новая ветка останется в состоянии С (со своими собственными изменениями), а в основной ветке будут изменения из обеих веток (изменения, внесенные коммитами С и D). Эта ветка перейдет в состояние Е.
Возможна и обратная ситуация, когда изменения из основной ветки вливаются в новую (мердж производится из новой ветки).
При этом мы можем вернуться в новую ветку и продолжить работу в ней (внести новые изменения и создать коммит F).
История изменений после слияния и нового коммита
Мердж конфликт (merge conflict) — ситуация, когда при слиянии веток в один или несколько файлов вносились независимые изменения. В некоторых случаях (например, если изменялись разные, не пересекающиеся части одного файла) git способен самостоятельно решить, как выполнять слияние таких файлов. Если автоматически это сделать не удалось — возникает конфликт. В таком случае необходимо самостоятельно указать, как выполнять слияние конфликтующих версий (решить конфликт, resolve merge conflict). Изменения, внесенные в процессе решения конфликта автоматически попадают в мердж коммит.
Чекаут (checkout) — переход на другое (существующее) состояние репозитория (на другой коммит или ветку). При этом все файлы в репозитории возвращаются в состояние, в котором они находились на момент указанного коммита. Если перед переходом в репозиторий были внесены изменения, которые были добавлены в репозиторий, но не попали в коммит — они будут перенесены «поверх» состояния после перехода. Как и при мердже, git попробует применить эти изменения к новому состоянию автоматически, при неудаче — возникает конфликт и изменения необходимо применить вручную.
Дифф (diff) — разница двух состояний (коммитов, веток, подготовленных или модифицированных файлов).
Трехсторонний дифф (three-way diff) — дифф, возникающий при мердже и решении конфликтов. Является разницей трех состояний: состояния репозитория в текущей ветке, состояния в целевой ветке слияния и общего состояния между этими ветками (состояния в базе слияния).
Черри-пик (cherry-pick) — процесс добавления в текущую ветку одного (или нескольких) коммитов из другой ветки, без необходимости выполнять слияние веток.
Реверт (revert) — отмена внесенных изменений (коммита или группы коммитов). В процессе реверта создается дополнительный коммит, который так же можно отменить при необходимости (вернув репозиторий в изначальное состояние). Реверт мердж коммита позволяет отменить выполненное ранее слияние веток.
Ребейз (rebase) — перенос изменений текущей ветки «поверх» другой ветки. При этом все коммиты текущей ветки, которых нет в целевой, удаляются из текущей и заново создаются в целевой ветке (последовательно применяются к состоянию в целевой ветке). Поскольку ребейз пересоздает коммиты заново и меняет существующую историю, его использование не рекомендуется при командной разработке. Ребейз в ветке, над которой работает несколько человек, может привести к потере чужих изменений и/или невозможности корректно выполнить слияние.
В данном случае коммит Е содержит изменения, которые вносились с момента последнего слияния или создания ветки (с момента коммита В). Т.е. коммит Е содержит в себе изменения из D. При выполнении ребейза git понимает, что эти изменения (E) уже присутствуют в целевой ветке (и окажутся в текущей после ребейза), потому нет необходимости копировать коммит Е, дублируя этим D.
Командная разработка
Наличие удаленного репозитория может быть полезным и при одиночной разработке: оно позволяет синхронизировать состояние проекта на разных компьютерах и просто сохранить проект на внешнем сервере.
Есть два варианта синхронизации изменений:
пулл (pull) — слияние состояния удаленного репозитория и локального (обычно — в отдельной ветке). Пулл может выполняться как для одной и той же ветки (с одинаковым именем), так и для разных. Пулл являет собою обычный мердж, но целевая ветка при этом находится не в том же репозитории, в котором выполняется пулл, а в удаленном. Как следствие, при пулле так же создается мердж коммит, пулл можно отменить (заревертить) и в его процессе может возникнуть мердж конфликт.
пуш (push) — обратный пуллу процесс. При пуше изменения из локального репозитория переносятся в удаленный. Пуш обновляет состояние текущей ветки в удаленном репозитории и не является мерджем (не создает дополнительные коммиты и не может привести к конфликтам). Если в ветке удаленного репозитория присутствуют коммиты, которых нет в локальном репозитории, сигнализируется ошибка о несовпадении истории изменений (non fast-forward merge), пуш выполнить не получится. В таком случае необходимо сначала синхронизировать состояние локального репозитория (получить недостающие коммиты с помощью пулла), и только после этого повторить процесс пуша.
Нередко возникает необходимость обновить информацию о состоянии удаленного репозитория (существующих ветках и коммитах в них) без выполнения слияния (пулла). Такой процесс называется фетчем (fetch). Таким образом, пулл является комбинаций фетча и мерджа: сперва обновляется информация о состоянии целевой ветки в удаленном репозитории, а затем ее изменения вливаются в текущую ветку в локальном репозитории.
основные понятия и термины
простые примеры терминов
применение git’a при командной разработке
некоторые проблемы, которые могут возникать при использовании git’a