Удаляет файлы с изменениями из рабочей директории и из staging area
Итак, у вас имеется настоящий Git-репозиторий и рабочая копия файлов для некоторого проекта. Вам нужно делать некоторые изменения и фиксировать «снимки» состояния (snapshots) этих изменений в вашем репозитории каждый раз, когда проект достигает состояния, которое вам хотелось бы сохранить.
Запомните, каждый файл в вашем рабочем каталоге может находиться в одном из двух состояний: под версионным контролем (отслеживаемые) и нет (неотслеживаемые). Отслеживаемые файлы — это те файлы, которые были в последнем снимке состояния проекта; они могут быть неизменёнными, изменёнными или подготовленными к коммиту. Если кратко, то отслеживаемые файлы — это те файлы, о которых знает Git.
Неотслеживаемые файлы — это всё остальное, любые файлы в вашем рабочем каталоге, которые не входили в ваш последний снимок состояния и не подготовлены к коммиту. Когда вы впервые клонируете репозиторий, все файлы будут отслеживаемыми и неизменёнными, потому что Git только что их извлек и вы ничего пока не редактировали.
Как только вы отредактируете файлы, Git будет рассматривать их как изменённые, так как вы изменили их с момента последнего коммита. Вы индексируете эти изменения, затем фиксируете все проиндексированные изменения, а затем цикл повторяется.
Определение состояния файлов
Основной инструмент, используемый для определения, какие файлы в каком состоянии находятся — это команда git status . Если вы выполните эту команду сразу после клонирования, вы увидите что-то вроде этого:
Это означает, что у вас чистый рабочий каталог, другими словами — в нем нет отслеживаемых измененных файлов. Git также не обнаружил неотслеживаемых файлов, в противном случае они бы были перечислены здесь. Наконец, команда сообщает вам на какой ветке вы находитесь и сообщает вам, что она не расходится с веткой на сервере. Пока что это всегда ветка master , ветка по умолчанию; в этой главе это не важно. В главе Ветвление в Git будут рассмотрены ветки и ссылки более детально.
Предположим, вы добавили в свой проект новый файл, простой файл README . Если этого файла раньше не было, и вы выполните git status , вы увидите свой неотслеживаемый файл вот так:
Понять, что новый файл README неотслеживаемый можно по тому, что он находится в секции «Untracked files» в выводе команды status . Статус Untracked означает, что Git видит файл, которого не было в предыдущем снимке состояния (коммите); Git не станет добавлять его в ваши коммиты, пока вы его явно об этом не попросите. Это предохранит вас от случайного добавления в репозиторий сгенерированных бинарных файлов или каких-либо других, которые вы и не думали добавлять. Мы хотели добавить README, так давайте сделаем это.
Отслеживание новых файлов
Для того чтобы начать отслеживать (добавить под версионный контроль) новый файл, используется команда git add . Чтобы начать отслеживание файла README , вы можете выполнить следующее:
Если вы снова выполните команду status , то увидите, что файл README теперь отслеживаемый и добавлен в индекс:
Вы можете видеть, что файл проиндексирован, так как он находится в секции «Changes to be committed». Если вы выполните коммит в этот момент, то версия файла, существовавшая на момент выполнения вами команды git add , будет добавлена в историю снимков состояния. Как вы помните, когда вы ранее выполнили git init , затем вы выполнили git add (файлы) — это было сделано для того, чтобы добавить файлы в вашем каталоге под версионный контроль. Команда git add принимает параметром путь к файлу или каталогу, если это каталог, команда рекурсивно добавляет все файлы из указанного каталога в индекс.
Индексация изменённых файлов
Давайте модифицируем файл, уже находящийся под версионным контролем. Если вы измените отслеживаемый файл CONTRIBUTING.md и после этого снова выполните команду git status , то результат будет примерно следующим:
Файл CONTRIBUTING.md находится в секции «Changes not staged for commit» — это означает, что отслеживаемый файл был изменён в рабочем каталоге, но пока не проиндексирован. Чтобы проиндексировать его, необходимо выполнить команду git add . Это многофункциональная команда, она используется для добавления под версионный контроль новых файлов, для индексации изменений, а также для других целей, например для указания файлов с исправленным конфликтом слияния. Вам может быть понятнее, если вы будете думать об этом как «добавить этот контент в следующий коммит», а не как «добавить этот файл в проект». Выполним git add , чтобы проиндексировать CONTRIBUTING.md , а затем снова выполним git status :
Теперь оба файла проиндексированы и войдут в следующий коммит. В этот момент вы, предположим, вспомнили одно небольшое изменение, которое вы хотите сделать в CONTRIBUTING.md до коммита. Вы открываете файл, вносите и сохраняете необходимые изменения и вроде бы готовы к коммиту. Но давайте-ка ещё раз выполним git status :
Что за чёрт? Теперь CONTRIBUTING.md отображается как проиндексированный и непроиндексированный одновременно. Как такое возможно? Такая ситуация наглядно демонстрирует, что Git индексирует файл в точности в том состоянии, в котором он находился, когда вы выполнили команду git add . Если вы выполните коммит сейчас, то файл CONTRIBUTING.md попадёт в коммит в том состоянии, в котором он находился, когда вы последний раз выполняли команду git add , а не в том, в котором он находится в вашем рабочем каталоге в момент выполнения git commit . Если вы изменили файл после выполнения git add , вам придётся снова выполнить git add , чтобы проиндексировать последнюю версию файла:
Сокращенный вывод статуса
Вывод команды git status довольно всеобъемлющий и многословный. Git также имеет флаг вывода сокращенного статуса, так что вы можете увидеть изменения в более компактном виде. Если вы выполните git status -s или git status --short вы получите гораздо более упрощенный вывод:
Новые неотслеживаемые файлы помечены ?? слева от них, файлы добавленные в отслеживаемые помечены A , отредактированные файлы помечены M и так далее. В выводе содержится два столбца — в левом указывается статус файла, а в правом модифицирован ли он после этого. К примеру в нашем выводе, файл README модифицирован в рабочем каталоге, но не проиндексирован, а файл lib/simplegit.rb модифицирован и проиндексирован. Файл Rakefile модифицирован, проиндексирован и ещё раз модифицирован, таким образом на данный момент у него есть те изменения, которые попадут в коммит, и те, которые не попадут.
Игнорирование файлов
Зачастую, у вас имеется группа файлов, которые вы не только не хотите автоматически добавлять в репозиторий, но и видеть в списках неотслеживаемых. К таким файлам обычно относятся автоматически генерируемые файлы (различные логи, результаты сборки программ и т. п.). В таком случае, вы можете создать файл .gitignore . с перечислением шаблонов соответствующих таким файлам. Вот пример файла .gitignore :
Первая строка предписывает Git игнорировать любые файлы заканчивающиеся на «.o» или «.a» — объектные и архивные файлы, которые могут появиться во время сборки кода. Вторая строка предписывает игнорировать все файлы заканчивающиеся на тильду (
), которая используется во многих текстовых редакторах, например Emacs, для обозначения временных файлов. Вы можете также включить каталоги log, tmp или pid; автоматически создаваемую документацию; и т. д. и т. п. Хорошая практика заключается в настройке файла .gitignore до того, как начать серьёзно работать, это защитит вас от случайного добавления в репозиторий файлов, которых вы там видеть не хотите.
К шаблонам в файле .gitignore применяются следующие правила:
Стандартные шаблоны являются глобальными и применяются рекурсивно для всего дерева каталогов.
Чтобы избежать рекурсии используйте символ слеш (/) в начале шаблона.
Чтобы исключить каталог добавьте слеш (/) в конец шаблона.
Можно инвертировать шаблон, использовав восклицательный знак (!) в качестве первого символа.
Glob-шаблоны представляют собой упрощённые регулярные выражения, используемые командными интерпретаторами. Символ ( * ) соответствует 0 или более символам; последовательность [abc] — любому символу из указанных в скобках (в данном примере a, b или c); знак вопроса ( ? ) соответствует одному символу; и квадратные скобки, в которые заключены символы, разделённые дефисом ( 2 ), соответствуют любому символу из интервала (в данном случае от 0 до 9). Вы также можете использовать две звёздочки, чтобы указать на вложенные каталоги: a/**/z соответствует a/z , a/b/z , a/b/c/z , и так далее.
Вот ещё один пример файла .gitignore :
В простейшем случае репозиторий будет иметь один файл .gitignore в корневом каталоге, правила из которого будут рекурсивно применяться ко всем подкаталогам. Так же возможно использовать .gitignore файлы в подкаталогах. Правила из этих файлов будут применяться только к каталогам, в которых они находятся. Например, репозиторий исходного кода ядра Linux содержит 206 файлов .gitignore .
Детальное рассмотрение использования нескольких .gitignore файлов выходит за пределы этой книги; детали доступны в справке man gitignore .
Просмотр индексированных и неиндексированных изменений
Допустим, вы снова изменили и проиндексировали файл README , а затем изменили файл CONTRIBUTING.md без индексирования. Если вы выполните команду git status , вы опять увидите что-то вроде:
Чтобы увидеть, что же вы изменили, но пока не проиндексировали, наберите git diff без аргументов:
Эта команда сравнивает содержимое вашего рабочего каталога с содержимым индекса. Результат показывает ещё не проиндексированные изменения.
Если вы хотите посмотреть, что вы проиндексировали и что войдёт в следующий коммит, вы можете выполнить git diff --staged . Эта команда сравнивает ваши проиндексированные изменения с последним коммитом:
Важно отметить, что git diff сама по себе не показывает все изменения сделанные с последнего коммита — только те, что ещё не проиндексированы. Такое поведение может сбивать с толку, так как если вы проиндексируете все свои изменения, то git diff ничего не вернёт.
Другой пример: вы проиндексировали файл CONTRIBUTING.md и затем изменили его, вы можете использовать git diff для просмотра как проиндексированных изменений в этом файле, так и тех, что пока не проиндексированы. Если наше окружение выглядит вот так:
Используйте git diff для просмотра непроиндексированных изменений
а так же git diff --cached для просмотра проиндексированных изменений ( --staged и --cached синонимы):
Мы будем продолжать использовать команду git diff различными способами на протяжении всей книги. Существует еще один способ просматривать эти изменения, если вы предпочитаете графический просмотр или внешнюю программу просмотра различий, вместо консоли. Выполнив команду git difftool вместо git diff , вы сможете просмотреть изменения в файле с помощью таких программ как emerge, vimdiff и других (включая коммерческие продукты). Выполните git difftool --tool-help чтобы увидеть какие из них уже установлены в вашей системе.
Коммит изменений
Теперь, когда ваш индекс находится в таком состоянии, как вам и хотелось, вы можете зафиксировать свои изменения. Запомните, всё, что до сих пор не проиндексировано — любые файлы, созданные или изменённые вами, и для которых вы не выполнили git add после редактирования — не войдут в этот коммит. Они останутся изменёнными файлами на вашем диске. В нашем случае, когда вы в последний раз выполняли git status , вы видели что всё проиндексировано, и вот, вы готовы к коммиту. Простейший способ зафиксировать изменения — это набрать git commit :
Эта команда откроет выбранный вами текстовый редактор.
Редактор устанавливается переменной окружения EDITOR — обычно это vim или emacs, хотя вы можете установить любой другой с помощью команды git config --global core.editor , как было показано в главе Введение).
В редакторе будет отображён следующий текст (это пример окна Vim):
Для ещё более подробного напоминания, что же именно вы поменяли, можете передать аргумент -v в команду git commit . Это приведёт к тому, что в комментарий будет также помещена дельта/diff изменений, таким образом вы сможете точно увидеть все изменения которые вы совершили.
Есть и другой способ — вы можете набрать свой комментарий к коммиту в командной строке вместе с командой commit указав его после параметра -m , как в следующем примере:
Итак, вы создали свой первый коммит! Вы можете видеть, что коммит вывел вам немного информации о себе: на какую ветку вы выполнили коммит ( master ), какая контрольная сумма SHA-1 у этого коммита ( 463dc4f ), сколько файлов было изменено, а также статистику по добавленным/удалённым строкам в этом коммите.
Запомните, что коммит сохраняет снимок состояния вашего индекса. Всё, что вы не проиндексировали, так и висит в рабочем каталоге как изменённое; вы можете сделать ещё один коммит, чтобы добавить эти изменения в репозиторий. Каждый раз, когда вы делаете коммит, вы сохраняете снимок состояния вашего проекта, который позже вы можете восстановить или с которым можно сравнить текущее состояние.
Игнорирование индексации
Несмотря на то, что индекс может быть удивительно полезным для создания коммитов именно такими, как вам и хотелось, он временами несколько сложнее, чем вам нужно в процессе работы. Если у вас есть желание пропустить этап индексирования, Git предоставляет простой способ. Добавление параметра -a в команду git commit заставляет Git автоматически индексировать каждый уже отслеживаемый на момент коммита файл, позволяя вам обойтись без git add :
Обратите внимание, что в данном случае перед коммитом вам не нужно выполнять git add для файла CONTRIBUTING.md , потому что флаг -a включает все файлы. Это удобно, но будьте осторожны: флаг -a может включить в коммит нежелательные изменения.
Удаление файлов
Для того чтобы удалить файл из Git, вам необходимо удалить его из отслеживаемых файлов (точнее, удалить его из вашего индекса) а затем выполнить коммит. Это позволяет сделать команда git rm , которая также удаляет файл из вашего рабочего каталога, так что в следующий раз вы не увидите его как «неотслеживаемый».
Если вы просто удалите файл из своего рабочего каталога, он будет показан в секции «Changes not staged for commit» (измененные, но не проиндексированные) вывода команды git status :
Затем, если вы выполните команду git rm , удаление файла попадёт в индекс:
После следующего коммита файл исчезнет и больше не будет отслеживаться. Если вы изменили файл и уже проиндексировали его, вы должны использовать принудительное удаление с помощью параметра -f . Это сделано для повышения безопасности, чтобы предотвратить ошибочное удаление данных, которые ещё не были записаны в снимок состояния и которые нельзя восстановить из Git.
Другая полезная штука, которую вы можете захотеть сделать — это удалить файл из индекса, оставив его при этом в рабочем каталоге. Другими словами, вы можете захотеть оставить файл на жёстком диске, но перестать отслеживать изменения в нём. Это особенно полезно, если вы забыли добавить что-то в файл .gitignore и по ошибке проиндексировали, например, большой файл с логами, или кучу промежуточных файлов компиляции. Чтобы сделать это, используйте опцию --cached :
В команду git rm можно передавать файлы, каталоги или шаблоны. Это означает, что вы можете сделать что-то вроде:
Обратите внимание на обратный слеш ( \ ) перед * . Он необходим из-за того, что Git использует свой собственный обработчик имён файлов вдобавок к обработчику вашего командного интерпретатора. Эта команда удаляет все файлы, имеющие расширение .log и находящиеся в каталоге log/ . Или же вы можете сделать вот так:
Эта команда удаляет все файлы, имена которых заканчиваются на
Перемещение файлов
В отличие от многих других систем контроля версий, Git не отслеживает перемещение файлов явно. Когда вы переименовываете файл в Git, в нём не сохраняется никаких метаданных, говорящих о том, что файл был переименован. Однако, Git довольно умён в плане обнаружения перемещений постфактум — мы рассмотрим обнаружение перемещения файлов чуть позже.
Таким образом, наличие в Git команды mv выглядит несколько странным. Если вам хочется переименовать файл в Git, вы можете сделать что-то вроде:
и это отлично сработает. На самом деле, если вы выполните что-то вроде этого и посмотрите на статус, вы увидите, что Git считает, что произошло переименование файла:
Однако, это эквивалентно выполнению следующих команд:
Git неявно определяет, что произошло переименование, поэтому неважно, переименуете вы файл так или используя команду mv . Единственное отличие состоит лишь в том, что mv — одна команда вместо трёх — это функция для удобства. Важнее другое — вы можете использовать любой удобный способ для переименования файла, а затем воспользоваться командами add/rm перед коммитом.
Одна из ключевых возможностей git — "откат" любых сделанных изменений буквально одной командой. Такое практически невозможно сделать без использования системы контроля версий. Только если помнить все изменения наизусть. В этом уроке мы поговорим про откат изменений, которые сделаны в рабочей директории, но ещё не попали в коммит.
Важно! Откат незакоммиченных изменений безвозвратен. Не существует никакой физической возможности получить эти изменения обратно, поэтому будьте крайне осторожны.
Неотслеживаемые файлы
Самая простая ситуация. Вы добавили новые файлы в репозиторий (или сгенерировали их как-то) и поняли, что они вам не нужны. В этом случае можно выполнить очистку:
Забавный факт: про эту команду знает не так много программистов. Вы можете удивить даже опытных ребят.
Изменённые файлы в рабочей директории
Для отмены изменений в таких файлах используется команда git restore . Причём git сам напоминает об этом при проверке статуса:
Файлы, добавленные для фиксации
С файлами, подготовленными к коммиту, можно поступить по-разному. Первый вариант — отменить изменения совсем, второй — переместить изменения из индекса в рабочую директорию. Второе полезно в том случае, если изменения нам нужны, но мы не хотим их коммитить сейчас.
И здесь снова помогает git. При выводе статуса он показывает нужную нам команду для перевода изменений в рабочую директорию:
Теперь, если нужно, можно выполнить git restore и окончательно отменить изменения в выбранных файлах.
Самостоятельная работа
Выполните все шаги из урока
Вам ответят команда поддержки Хекслета или другие студенты.
Нашли опечатку или неточность?
Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.
Что-то не получается или материал кажется сложным?
- задайте вопрос. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
- расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
- изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете
- Статья «Как учиться и справляться с негативными мыслями»
- Статья «Ловушки обучения»
- Статья «Сложные простые задачи по программированию»
- Урок «Как эффективно учиться на Хекслете»
- Вебинар «Как самостоятельно учиться»
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.
Существует замечательная книга Pro Git, в которой подробно описаны все команды и возможности гита. Но после ее прочтения у многих остается непонимание того, как это все использовать на практике. В частности, у программистов разного уровня часто возникают вопросы о том, как работать с ветками в Git, когда их заводить и как мержить между собой. Порой мне попадались очень «оригинальные» и неоправданно усложненные схемы работы с гитом. В то время как в сообществе программистов уже сформировалась схема работы с гитом и ветками в нем. В этой статье я хочу дать краткий обзор основных моментов при работе с Git, и описать «классическую» схему работы с ветками. Многое из того что описано в этой статье будет справедливо и для других систем управления версиями.
Эта статья может быть полезна для программистов, которые только начинают осваивать Git, или какую-то другую систему управления версиями. Для опытных программистов эта статья покажется очень простой и банальной.
Для начала давайте разберемся с тем что такое ветка и коммит.
Коммит
Можно сказать, что коммит это основной объект в любой системе управления версиями. В нем содержится описание тех изменений, которые вносит пользователь в код приложения. В Git коммит состоит из нескольких так называемых объектов. Для простоты понимания можно считать, что коммиты это односвязный список, состоящий из объектов в которых содержаться измененные файлы, и ссылка на предыдущий коммит.
У коммита есть и другие свойства. Например, дата коммита, автор, комментарий к коммиту и т.п.
В качестве комментария обычно указывают те изменения, которые вносит этот коммит в код, или название задачи которую он решает.
Git это распределенная система управления версиями. Это значит, что у каждого участника проекта есть своя копия репозитория, которая находиться в папке “.git”, которая расположена в корне проекта. Именно в этой папке хранятся все коммиты и другие объекты Git. Когда вы работаете с Git, он в свою очередь работает с этой папкой.
Завести новый репозиторий очень просто, это делается командой
Таким образом у вас получиться новый пустой репозиторий. Если вы хотите присоединиться к разработке уже имеющегося проекта, то вам нужно будет скопировать этот репозиторий в свою локальную папку с удаленного репозитория. Делается это так:
git clone <url удаленного репозитория>
После чего в текущей папке появляется директория .git в которой и будет содержаться копия удаленного репозитория.
Существует несколько основных областей в которых находиться код.
- Рабочая директория – это файлы в корне проекта, тот код с которым вы работаете.
- Локальный репозиторий — она же директория “.git”. В ней хранятся коммиты и другие объекты.
- Удаленный репозиторий – тот самый репозиторий который считается общим, в который вы можете передать свои коммиты из локального репозитория, что бы остальные программисты могли их увидеть. Удаленных репозиториев может быть несколько, но обычно он бывает один.
- Есть еще одна область, с пониманием которой обычно бывают проблемы. Это так называемая область подготовленных изменений (staging area). Дело в том, что перед тем как включить какие-то изменения в коммит, нужно вначале отметить что именно вы хотите включить в этот коммит. В своей рабочей директории вы можете изменить несколько файлов, но в один конкретный коммит включать не все эти изменения.
git add <имя/файла>
При этом можно использовать маски со звездочкой.
Потом вы делаете коммит в свой локальный репозиторий
git commit –m “Комментарий к коммиту”
Когда коммитов накопиться достаточно много, чтобы ими можно было поделиться, вы выполняете команду
После чего ваши коммиты уходят в удаленный репозиторий.
Если нужно получить изменения из удаленного репозитория, то нужно выполнить команду
После этого, в вашем локальном репозитории появятся те изменения, которые были отправлены другими программистами.
Код в рабочей области проекта образуется применением тех изменений, которые содержаться в коммитах. У каждого коммита есть свое имя, которое представляет собой результат хеш функции sha-1 от содержимого самого коммита.
Просмотреть коммиты можно при помощи команды
Формат ответа этой команды по дефолту не очень удобен. Вот такая команда выведет ответ в более читаемом виде
git log --pretty=format:"%H [%cd]: %an - %s" --graph --date=format:%c
Что бы закончить просмотр нужно нажать на клавишу q
Посмотреть, что находиться в рабочей директории и staging area можно командой
Рабочую директорию можно переключить на предыдущее состояние выполнив команду
git checkout <hash коммита>
Только перед тем как это делать выполните git status и убедитесь, что у вас нет никаких локальных и не зафиксированных изменений. Иначе Git не поймет, как ему переключаться. git status подскажет вам что можно сделать с локальными изменениями что бы можно было переключиться. Этого правила следует придерживаться и при всяких других переключениях рабочей области.
Ветка
Ветка в Git это подвижный указатель на один из коммитов. Обычно ветка указывает на последний коммит в цепочке коммитов. Ветка берет свое начало от какого-то одного коммита. Визуально это можно представить вот так.
Сделать новую ветку и переключиться на нее можно выполнив команды
git pull
git checkout –b <имя новой ветки>
Просто сделать ветку, не переключаясь на нее можно командой
git branch <имя ветки>
переключиться на ветку
git checkout <имя ветки>
Важно понимать, что ветка берет свое начало не от ветки, а от последнего коммита который находиться в той ветке, в которой вы находились.
Ветка обычно заканчивается специальным merge коммитом, который говорит, что ветку нужно объединить с какой-то другой веткой. В merge коммите содержатся две ссылки на два коммита которые объединяются в одну ветку.
Существует другая ситуация при объединении веток, в которой merge может произойти без merge commit. Дело в том, что если в одной из веток не произошло никаких изменений, то необходимость в merge commit с двумя предками отпадает. В таком случае, при слиянии веток, Git просто сделает пометку о том, что дальше будут идти коммиты той ветки с которой эта ветка была объединена. Такая схема merge называется слияние-перемотка (fast-forward merge), визуально это можно представить вот так.
Во всех этих случаях, после того, как ветка объединяется с другой веткой, все коммиты сделанные в ней, попадают в ветку с которой она была объединена. Так же важно понимать, что merge это не двунаправленная операция. Если смержить ветку задачи в мастер ветку, то в мастер ветке появится код, который находился в ветке задачи, а в ветке задачи не появиться новый код из мастер ветки. Если нужно что бы это произошло, нужно смержить мастер ветку в ветку задачи.
Что бы смержить одну ветку в другую нужно вначале переключиться на ту ветку, в которую вы хотите смержить
git checkout <имя ветки>
Потом получить последние изменения сделанные в этой ветке выполнив
Затем выполнить команду
git merge <имя ветки>
Так выглядит работа с ветками в общих чертах.
- Другой программист мог изменить код, в том числе внести такие изменения, которые повлияют на решение задачи, для которой вы заводите новую ветку. Эти изменения могут вам пригодиться при решении своей задачи.
- Из-за этих изменений вы можете получить конфликт при мерже.
- Больше шанс что у вас получится merge commit. Это не так плохо, как два предыдущих пункта. Но если можно избежать лишнего коммита, то почему бы этого не сделать?
Популярные схемы работы с ветками в Git
Теперь можно описать популярные схемы работы с ветками в гите.
Ветки нужны для того, чтобы программисты могли вести совместную работу над проектом и не мешать друг другу при этом. При создании проекта, Git создает базовую ветку. Она называется master веткой. Она считается центральной веткой, т.е. в ней содержится основной код приложения.
Классическая схема работы с ветками
Обычно перед тем как взяться за решение какой-то задачи, программист заводит новую ветку от последнего рабочего коммита мастер ветки и решает задачу в этой новой ветке. В ходе решения он делает ряд коммитов, после этого тестирует код непосредственно в ветке задачи. А после того как задача решена, делают merge обратно в мастер ветку. Такую схему работы часто используют с юнит тестами и автоматизированным деплоем. Если юнит тесты будут покрывать весь код, то можно настроить деплой так, что вначале будут прогоняться все тесты в ветке задачи. А после этого, если они прошли успешно, будет происходить merge и деплой. При такой схеме можно добиться полной автоматизации при тестировании и деплои.
Именная ветка
Неопытные программисты заводят себе именную ветку и работают всегда в ней. Они решают по одной задачи за раз, и когда заканчивают решение одной из задач, делают новый Pull запрос через Web интерфейсе (об этом чуть ниже). Недостаток этого подхода в том, что так можно решать только одну задачу и нельзя быстро переключиться на решение другой задачи. Еще один недостаток в том, что ветки так со временем будут все сильнее расходиться и код в ветке программиста рано или поздно устареет относительно мастер ветки и его придется обновить. Для этого можно либо смержить мастер ветку в ветку программиста, либо завести новую ветку для этого программиста от последнего рабочего состояния в мастер ветке. Правда к тому времени, как это произойдет программист уже может освоить гит в достаточной мере что бы перейти на “классическую” схему работы. Таким образом эта схема имеет место быть для неопытных пользователей Git.
Схема с dev веткой
Другая схема очень похожа на классическую, только в ней помимо мастер ветки есть еще девелоперская ветка, которая деплоится на тестовый сервер. Такую ветку обычно называют dev. Схема работы при этом такая. Программист перед выполнением новой задачи заводит для нее ветку от последнего рабочего состояния в мастер ветке. Когда он заканчивает работу над задачей, то мержит ветку задачи в dev ветку самостоятельно. После этого, совместными усилиями задача тестируется на тестовом сервере вместе с остальными задачами. Если есть ошибки, то задачу дорабатывают в той же ветке и повторно мержат с dev веткой. Когда тестирование задачи заканчивается, то ВЕТКУ ЗАДАЧИ мержат с мастер веткой. Важно заметить, что в этой схеме работы с мастер веткой нужно мержить ветку задачи, а не dev ветку. Ведь в dev ветке будут содержаться изменения, сделанные не только в этой задаче, но и в других и не все эти изменения могут оказаться рабочими. Мастер ветка и dev ветка со временем будут расходиться, поэтому при такой схеме работы периодически заводят новую dev ветку от последнего рабочего состояния мастер ветки. Недостатком этого подхода является избыточность, по сравнению с классической схемой. Такую схему работы с ветками часто используют если в проекте нет автоматизированных тестов и все тестирование происходит вручную на сервере разработки.
Так же следует отметить что эти схемы работы можно комбинировать между собой, если в этом есть какая-то необходимость.
Pull запросы
Про эту кнопку и пойдет речь дальше.
Если программист достаточно опытный и ответственный, то он обычно сам сливает свой код в мастер ветку. В противном случае программист делает так называемый Pull запрос. Pull запрос это по сути дела запрос на разрешение сделать merge. Pull запрос можно сделать из web интерфейса Git, или при помощи команды git request-pull. После того как Pull запрос создан, остальные участники могут увидеть это, просмотреть тот код который программист предлагает внести в проект, и либо одобрить этот код либо нет. Merge через pull запросы имеет свои плюсы и минусы. Минус в том, что для тесной команды опытных программистов такой подход будет лишним. Это будет только тормозить работу и вносить в нее оттенки бюрократии.
С другой стороны, если в проекте есть не опытные программисты, которые могут сломать код, то Pull запросы могут помочь избежать ошибок, и быстрее обучить этих программистов наблюдая за тем какие изменения они предлагают внести в код.
Так же Pull запросы подходят для широкого сообщества программистов, работающих с открытым исходным кодом. В этом случае нельзя заранее сказать что-то о компетенции таких разработчиков и о том, что они хотят изменить в коде.
Конфликты
Конфликты возникают при мердже веток если в этих ветках одна и та же строка кода была изменена по-разному. Тогда получается, что Git не может сам решить какое из изменений нужно применить и он предлагает вручную решить эту ситуацию. Это замедляет работу с кодом в проекте. Избежать этого можно разными методами. Например, можно распределять задачи так, чтобы связанные задачи не выполнялись одновременно различными программистами.
Другой способ избежать этого, это договориться о каком-то конкретном стиле кода. Тогда программисты не будут менять форматирование кода и вероятность того, что они изменят одну и ту же строчку станет ниже.
Еще один хороший совет, который поможет вам избежать конфликтов при работе в команде, это вносить минимум изменений в код при решении задач. Чем меньше строчек вы поменяли, тем меньше вероятность что вы измените ту же самую строку что и другой программист в другой задаче.
После того, как в мастер ветке достигается состояние, которое можно считать стабильным оно отмечается тегом с версией этого состояния. Это и есть то что называют версией программы.
Делается это вот так
Что бы передать ветки в удаленный репозиторий нужно выполнить команду
Теги удобны еще и тем, что можно легко переключиться на то состояние кода которое отмечено тегом. Делается это с помощью все той же команды
git checkout <имя тега>
Различные системы деплоя и автоматизированной сборки используют теги для идентификации того состояния, которое нужно задеплоить или собрать. Так сделано потому, что если мы будем собирать или деплоить код последней версии, то есть риск, что какой-то другой программист в этот момент внесет какие-то изменения в мастер ветку, и мы соберем не то что хотели. К тому же так будет проще переключаться между рабочими и проверенными состояниями проектов.
Это обзор основных моментов при работе с Git. Если вы хотите узнать про Git больше, то я вам посоветую прочитать книгу Pro Git. Вот здесь.
В этой статье была приведена упрощенная схема представления коммитов. Но перед тем как ее написать я решил разобраться как именно хранятся коммиты на диске. Если вас тоже заинтересует этот вопрос, то вы можете прочитать об этом вот здесь.
Git сегодня - это очень популярная система контроля версий. Поэтому шпаргалка по Git, состоящая из основных команд - это то, что может вам пригодиться.
git add
Команда git add добавляет содержимое рабочей директории в индекс (staging area) для последующего коммита. По умолчанию git commit использует лишь этот индекс, так что вы можете использовать git add для сборки слепка вашего следующего коммита.
git status
Команда git status показывает состояния файлов в рабочей директории и индексе: какие файлы изменены, но не добавлены в индекс; какие ожидают коммита в индексе. Вдобавок к этому выводятся подсказки о том, как изменить состояние файлов.
git diff
Команда git diff используется для вычисления разницы между любыми двумя Git деревьями. Это может быть разница между вашей рабочей директорией и индексом (собственно git diff ), разница между индексом и последним коммитом ( git diff --staged ), или между любыми двумя коммитами ( git diff master branchB ).
git difftool
Команда git difftool просто запускает внешнюю утилиту сравнения для показа различий в двух деревьях, на случай если вы хотите использовать что-либо отличное от встроенного просмотрщика git diff .
git commit
Команда git commit берёт все данные, добавленные в индекс с помощью git add , и сохраняет их слепок во внутренней базе данных, а затем сдвигает указатель текущей ветки на этот слепок.
git reset
Команда git reset , как можно догадаться из названия, используется в основном для отмены изменений. Она изменяет указатель HEAD и, опционально, состояние индекса. Также эта команда может изменить файлы в рабочей директории при использовании параметра --hard , что может привести к потере наработок при неправильном использовании, так что убедитесь в серьёзности своих намерений прежде чем использовать его.
git rm
Команда git rm используется в Git для удаления файлов из индекса и рабочей директории. Она похожа на git add с тем лишь исключением, что она удаляет, а не добавляет файлы для следующего коммита.
git mv
Команда git mv — это всего лишь удобный способ переместить файл, а затем выполнить git add для нового файла и git rm для старого.
git clean
Команда git clean используется для удаления мусора из рабочей директории. Это могут быть результаты сборки проекта или файлы конфликтов слияний.
git branch
Команда git branch — это своего рода “менеджер веток”. Она умеет перечислять ваши ветки, создавать новые, удалять и переименовывать их.
git checkout
Команда git checkout используется для переключения веток и выгрузки их содержимого в рабочую директорию.
git merge
Команда git merge используется для слияния одной или нескольких веток в текущую. Затем она устанавливает указатель текущей ветки на результирующий коммит.
git mergetool
Команда git mergetool просто вызывает внешнюю программу слияний, в случае если у вас возникли проблемы слияния.
git log
Команда git log используется для просмотра истории коммитов, начиная с самого свежего и уходя к истокам проекта. По умолчанию, она показывает лишь историю текущей ветки, но может быть настроена на вывод истории других, даже нескольких сразу, веток. Также её можно использовать для просмотра различий между ветками на уровне коммитов.
git stash
Команда git stash используется для временного сохранения всех незакоммиченных изменений для очистки рабочей директории без необходимости коммитить незавершённую работу в новую ветку.
git tag
Команда git tag используется для задания постоянной метки на какой-либо момент в истории проекта. Обычно она используется для релизов.
Не так уж много команд в Git требуют сетевого подключения для своей работы, практически все команды оперируют с локальной копией проекта. Когда вы готовы поделиться своими наработками, всего несколько команд помогут вам работать с удалёнными репозиториями.
git fetch
Команда git fetch связывается с удалённым репозиторием и забирает из него все изменения, которых у вас пока нет и сохраняет их локально.
git pull
Команда git pull работает как комбинация команд git fetch и git merge , т.е. Git вначале забирает изменения из указанного удалённого репозитория, а затем пытается слить их с текущей веткой.
git push
Команда git push используется для установления связи с удалённым репозиторием, вычисления локальных изменений отсутствующих в нём, и собственно их передачи в вышеупомянутый репозиторий. Этой команде нужно право на запись в репозиторий, поэтому она использует аутентификацию.
git remote
Команда git remote служит для управления списком удалённых репозиториев. Она позволяет сохранять длинные URL репозиториев в виде понятных коротких строк, например "origin", так что вам не придётся забивать голову всякой ерундой и набирать её каждый раз для связи с сервером. Вы можете использовать несколько удалённых репозиториев для работы и git remote поможет добавлять, изменять и удалять их.
git archive
Команда git archive используется для упаковки в архив указанных коммитов или всего репозитория.
git submodule
Команда git submodule используется для управления вложенными репозиториями. Например, это могут быть библиотеки или другие, используемые не только в этом проекте ресурсы. У команды submodule есть несколько под-команд — add , update , sync и др. — для управления такими репозиториями.
git show
Команда git show отображает объект в простом и человекопонятном виде. Обычно она используется для просмотра информации о метке или коммите.
git shortlog
Команда git shortlog служит для подведения итогов команды git log . Она принимает практически те же параметры, что и git log , но вместо простого листинга всех коммитов, они будут сгруппированы по автору.
git describe
Команда git describe принимает на вход что угодно, что можно трактовать как коммит (ветку, тег) и выводит более-менее человекочитаемую строку, которая не изменится в будущем для данного коммита. Это может быть использовано как более удобная, но по-прежнему уникальная, замена SHA-1.
В Git есть несколько команд, используемых для нахождения проблем в коде. Это команды для поиска места в истории, где проблема впервые проявилась и собственно виновника этой проблемы.
git bisect
Команда git bisect — это чрезвычайно полезная утилита для поиска коммита в котором впервые проявился баг или проблема с помощью автоматического бинарного поиска.
git blame
Команда git blame выводит перед каждой строкой файла SHA-1 коммита, последний раз менявшего эту строку и автора этого коммита. Это помогает в поисках человека, которому нужно задавать вопросы о проблемном куске кода.
git grep
Команда git grep используется для поиска любой строки или регулярного выражения в любом из файлов вашего проекта, даже в более ранних его версиях.
Если вы только начинаете работать с Git, или переходите на Git с другой СКВ, то такая шпаргалка может вам очень пригодиться.
Читайте также: