Справочники, инструменты, документация

Первоначальная настройка Git

В состав Git'а входит утилита `git config`, которая позволяет просматривать и устанавливать параметры, контролирующие все аспекты работы Git'а и его внешний вид. Настройки на каждом следующем уровне настройки из предыдущих уровней.

Основные настройки

Опция --global применит эти настройки для всего, что вы делаете в этой системе. Если для каких-то отдельных проектов нужно указать другое имя или электронную почту, можно выполнить эту же команду без параметра --global в каталоге с нужным проектом.

git config [--global] user.name "<имя_пользователя>" git config [--global] user.email "<эмейл>" git config [--global] core.editor <имя_программы> - позволяет указать редактор текста по умолчанию. git config [--global] merge.tool <имя_программы> - позволяет указать утилиту сравнения для разрешения конфликтов слияния. git config --list - выводит ключи и значение ключей настроек. git config <ключ> - выводит значение ключа из настроек. git config --global color.ui auto - устанавливает вывод цветов для комманд в консоли. git config --global core.autocrlf true - устанавливает игнорирование окончания строк.

Алиасы

git config [--global] alias.<имя_алиаса> '<команды>' - создание алиаса. git <имя_алиаса> - вызов алиаса.

git config --global alias.last 'log -1 HEAD'

Справка

git help <команда> git <команда> --help - выводит справку по команде.

Основы Git

Создание Git-репозитория

git init - создает в текущем каталоге новый подкаталог с именем .git содержащий все необходимые файлы репозитория - основу Git-репозитория. git clone [--bare] <url> [<имя_результирующего_каталога>] - создает каталог с именем окончания url, инициализирует в нем каталог .git [только каталог .git], скачивает все данные для этого репозитория и создает (checks out) рабочую копию последней версии, при указании <имя_результирующего_каталога> равным ./ произведет клонирование в текущий каталог.

Запись изменений в репозиторий

Каждый файл в рабочем каталоге может находиться в одном из двух состояний:

  • под версионным контролем (отслеживаемые файлы) - это те файлы, которые были в последнем слепке состояния проекта (snapshot); они могут быть неизмененными, измененными или подготовленными к коммиту (staged);
  • не под версионным контролем (неотслеживаемые файлы) - это все остальное, любые файлы в вашем рабочем каталоге, которые не входили в ваш последний слепок состояния и не подготовлены к коммиту.

Когда впервые производится клонирование репозитория, все файлы будут отслеживаемыми и неизмененными, потому что их только взяли из хранилища (checked them out) и ничего пока не редактировали.

Как только будут отредактированы файлы, Git будет рассматривать их как измененные, т.к. они стали измененные с момента последнего коммита. Затем индексируются (stage) эти изменения и затем фиксируются индексированные изменения, а затем цикл повторяется.

Статус "неотслеживаемый файл", означает, что Git видит файл, отсутствующий в предыдущем снимке состояния (коммите); Git не станет добавлять его в коммиты, пока его явно об этом не попросят.

File Status Lifecycle

+-----------+    +------------+   +----------+      +--------+
| untracked |    | unmodified |   | modified |      | staged |
+-----------+    +------------+   +----------+      +--------+
      | add the file    |               |                |
      |---------------->|               |                |
      |                 | edit the file |                |
      |                 |-------------->|                |
      |                 |               | stage the file |
      |                 |               |--------------->|
      | remove the file |               |                |
      |<----------------|               |                |
      |                 | commit        |                |
      |                 |<-------------------------------|
+-----------+    +------------+   +----------+      +--------+
| untracked |    | unmodified |   | modified |      | staged |
+-----------+    +------------+   +----------+      +--------+

git status - выводит результат определения, какие файлы в каком состоянии находятся. git status -sb - выводит результат определения, какие файлы в каком состоянии находятся в сокращенном варианте. git add [-f] <новый_файл> - начинает [принудительно, даже если файл игнорируется] отслеживать (добавить под версионный контроль) новый файл, также принимает параметром путь к файлу или каталогу, если это каталог, команда рекурсивно добавляет (индексирует) все файлы в данном каталоге. git add [-f] <файл> - индексирует [принудительно, даже если файл игнорируется] отслеживаемый файл, если он был изменен в рабочем каталоге. Если файл изменился после выполнения git add, то придется снова выполнить git add, чтобы проиндексировать последнюю версию файла для того чтобы он попал в коммит. git hash-object <файл> - вычисляет hash-файла.

Игнорирование файлов

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

К шаблонам в файле .gitignore применяются следующие правила:

  • пустые строки, а также строки, начинающиеся с #, игнорируются;
  • можно использовать стандартные glob шаблоны;
  • можно заканчивать шаблон символом слэша / для указания каталога;
  • можно инвертировать шаблон, использовав восклицательный знак ! в качестве первого символа.

Glob-шаблоны представляют собой упрощенные регулярные выражения используемые командными интерпретаторами:

  • символ * соответствует 0 или более символам;
  • последовательность [abc] - любому символу из указанных в скобках (в данном примере a, b или c);
  • знак вопроса ? соответствует одному символу;
  • [0-9] соответствует любому символу из интервала (в данном случае от 0 до 9).

Атрибуты файлов

Для автоматического задания всем файлам атрибутов используется файл .gitattributes с перечислением комманд:

  • * text=auto - говорит что при сравнении, все файлы текстового формата, обрабатывать с окончаниями строк в виде LF.

Глобальное игнорирование файлов

git config --global core.excludesfile ~/.gitignore - теперь все шаблоны из файла ~/.gitignore будут дополнять шаблоны из локальных файлов .gitignore для игнорирования файлов.

Просмотр индексированных и неиндексированных изменений

git diff [--cached] - выводит то, что конкретно поменялось, а не только какие файлы были изменены. Эта команда сравнивает содержимое вашего рабочего каталога с содержимым индекса. Результат показывает еще не проиндексированные изменения.

С флагом --cached (--staged) - сравнивает индексированные изменения с последним коммитом. git diff [<хэш_последовательность_коммита>] - сравнивает текущее состояние с указанным коммитом или последним коммитом, если он не указан. git diff <хэш_последь_коммита1>..<хэш_послед_коммита2> [<имя_файла>] - сравнивает коммиты [для указанного файла]. git diff <ветка1>..<ветка2> [<имя_файла>] - сравнивает ветки [для указанного файла].

Параметр -w - игнорирует пробелы при сравнении строк. Ключ --stat позволяет видеть измененные файлы, как в структуре выводимой командой git log --stat.

Фиксация изменений

git commit - фиксирует изменения. Эта команда откроет выбранный текстовый редактор для написания коментария.

  • с параметром -v - в комментарий будет также помещена дельта /diff изменений, таким образом можно точно увидеть все, что сделано. После выхода из редактора, Git создает коммит с этим сообщением (удаляя комментарии и вывод diff'а);
  • также можно набрать свой комментарий к коммиту в командной строке вместе с командой commit, указав его после параметра -m;
  • добавление параметра -a в команду git commit заставляет Git автоматически индексировать каждый уже отслеживаемый на момент коммита файл, позволяя обойтись без git add.

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

Отмена изменений

git commit --amend - отменяет текущий коммит, именно коммит, а не сами изменения файлов. Перезаписывает его.

Правила составления комментариев к коммиту

  1. Заголовок от тела отделяется пустой строкой - длиной менее 50 символов, обобщающей сделанные изменения, затем идет пустая строка и затем более подробное описание. Текст до первой пустой строки в комментарии считается заголовком коммита. Комментарий после -m считается заголовком.
  2. Заголовок комментария 50 символов - эта длина заголовка гарантирует его читабельность, а также заставляет автора задуматься о самой краткой и четкой формулировке для описания происходящего.
  3. Заголовок начинается с заглавной буквы.
  4. После заголовка не ставится точка.
  5. В заголовке используется повелительное наклонение - буквально означает: форма глагола, выражающая волеизъявления (приказ, просьбу или совет):
    Update getting started documentation - верно Fixed bug with Y - не верно

Правильно составленный заголовок коммита должен завершать следующее предложение: If applied, this commit will <заголовок_коммита> Или: This changes <заголовок_коммита> - Эти изменения <заголовок_коммита>. 6. Переход на следующую строку в теле осуществляется на 72 символах - для того чтобы Git мог свободно расставлять отступы и все еще влезать в сумме в 80 символов. 7. В теле должны быть ответы на вопросы "что" и "почему", а не "как" - должны быть описаны причины, по которым были внесены изменения - описана ситуация до внесения изменения (и что было с ней не так), ситуацию после и то, почему был выбран именно такой способ решения задачи.

Структура:

<тип>[(<область_коммита>)]: <заголовок>

[<тело>]

[<колонтитул>]

Где <тип>:

  • feat - новая фича для пользователя, а не, например, новая функция для скрипта сборки;
  • fix - исправление ошибки для пользователей, а не исправление скрипта сборки;
  • docs - изменения в документации;
  • style - форматирование, отсутствующие точки с запятой и т. д .; без изменения производственного кода;
  • refactor - рефакторинг производственного кода, например, переименование переменной;
  • test - добавление недостающих тестов, рефакторинг тестов; без изменения производственного кода;
  • chore - обновление рутинных задач и т. д.; без изменения производственного кода.

<область_коммита> - номер задачи, часть проекта на который происходит воздействие.

Удаление файлов

git rm <файл> - удаляет файл из Git'а, а также удаляет файл из рабочего каталога, так что в следующий раз не будет видно его как "неотслеживаемый".

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

  • опция --cached - удаляет файл из индекса, оставив его при этом в рабочем каталоге.

В команду git rm можно передавать файлы, каталоги или glob-шаблоны.

Перемещение файлов

git mv <файл_откуда> <файл_куда> - переименовывает файл.

Просмотр истории коммитов

git show <хеш_коммита> - отображает данные коммита по его хешу. git show <хеш_коммита>:<файл> - отображает содержимое файла в коммите.

Команда log

git log - выводит список коммитов созданных в данном репозитории в обратном хронологическом порядке, отображает каждый коммит вместе с его контрольной суммой SHA-1, именем и электронной почтой автора, датой создания и комментарием.

  • параметр -p - показывает дельту (разницу/diff), привнесенную каждым коммитом. Этот параметр показывает ту же самую информацию плюс внесенные изменения, отображаемые непосредственно после каждого коммита;
  • параметр -<n> - ограничивает вывод до <n>-х последних записей;
  • параметр -w - игнорирует пробелы при сравнении строк;
  • параметр -m - указывает коммитам слияния (merge) быть как обычные коммиты при выводе;
  • опция --word-diff после команды git log -p - выводит дельту по словам вместо обычной дельты по строкам. Добавленное слово заключено в {+ +}, а удаленное в [- -];
  • опция -U1 - сокращает обычные три строки контекста в выводе команды diff до одной строки;
  • параметр --stat выводит под каждым коммитом список измененных файлов, количество измененных файлов, и количество добавленных и удаленных строк в этих файлах;
  • параметр --pretty - позволяет изменить формат вывода лога. Вариант параметра равный oneline выводит каждый коммит в одну строку, для удобства просмотра большого количества коммитов. Варианты параметры short, full, и fuller, практически не меняя формат вывода, позволяют выводить меньше или больше деталей соответственно. Вариант параметра format, позволяет полностью создать собственный формат вывода лога. Указывается как: --pretty=format:"<формат_вывода>".

git log -p <файл> - выводит все коммиты и их дельту (разницу/diff), которые были применены к файлу. git log -- <файл> - выводит все коммиты которые были применены к файлу.

Наиболее полезные параметры формата

Параметр Описание выводимых данных
%H Хеш коммита
%h Сокращенный хеш коммита
%T Хеш дерева
%t Сокращенный хеш дерева
%P Хеши родительских коммитов
%p Сокращенные хеши родительских коммитов
%an Имя автора - это человек, изначально сделавший работу
%ae Электронная почта автора
%ad Дата автора (формат соответствует параметру --date=)
%ar Дата автора, относительная (пр. "2 мес. назад")
%cn Имя коммитера - это человек, который последним применил эту работу
%ce Электронная почта коммитера
%cd Дата коммитера
%cr Дата коммитера, относительная
%s Комментарий
%d Имя ссылки (ветки)

%C([<тип> ]<цвет>) - переключает вывод на указаный формат, где:

  • <тип> - тип отображения (bold, dim, ul, blink, reverse, italic, strike);
  • <цвет> - цвет отображения (normal, black, red, green, yellow, blue, magenta, cyan white).

%C(reset) - сбрасывает формат вывода.

Параметры oneline и format полезны с другим параметром команды git log --graph. Этот параметр добавляет ASCII-граф, показывающий историю ветвлений и слияний.

Другие параметы

Параметр Описание
--shortstat Показывать только строку changed/insertions/deletions от вывода с опцией --stat
--name-only Показывать список измененных файлов после информации о коммите
--name-status Выводить список измененных файлов вместе с информацией о добавлении/изменении/удалении
--abbrev-commit Выводить только первые несколько символов контрольной суммы SHA-1 вместо всех 40
--relative-date Выводить дату в относительном формате (например, "2 weeks ago") вместо полной даты

Дополнительное ограничения вывода

Параметры --since и --until - ограничивают по времени. Такие команды могут работать с множеством форматов -можно указать точную дату ("2008-01-15") или относительную дату, такую как "2 years 1 day 3 minutes ago". Опция --grep позволяет искать по ключевым словам в сообщении.

Дополнительные опции

Опция Описание
--since, --after Ограничить коммиты теми, которые сделаны после указанной даты
--until, --before Ограничить коммиты теми, которые сделаны до указанной даты
--author Показать только те коммиты, автор которых соответствует указанной строке
--committer Показать только те коммиты, коммитер которых соответствует указанной строке

Использование графического интерфейса для визуализации истории

gitk - это наглядный вариант git log, к тому же он принимает почти те же фильтрующие опции, что и git log. Если набирать в командной строке gitk, находясь в проекте то можно увидеть визуализацию истории.

Общий лог git shortlog

git shortlog - выводит пользователей вместе с их коммитами. git shortlog -- <файл> - выводит все коммиты которые были применены к файлу.

git shortlog -n --format="[%H] %s" -- <файл> - выводит коммиты пользователей с их хешем отсортированные по количеству коммитов для файла.

Лог команд git reflog

git reflog [show] - выводит список команд которые были применены [, применяет все параметры как и у команды git log если возможно]. У каждой примененной команды есть свой идентификатор (хеш) состояния после пременения этой команды, на который можно в случае чего вернуться с помощью: git reset --hard <хеш>.

Аннотация файла git blame

git blame <файл> - выводит информацию о том, какие коммиты модифицировали каждую строку файла в последний раз. Строки которые начинаются с ^ - это те строки, которые находятся здесь со времен первого коммита для этого файла.

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

Откат к нужной версии

git reset --hard <хэш_последовательность_коммита> - производит откат к нужной версии коммита. git reset --hard HEAD - производит откат на HEAD-коммит ветки. git reset --soft HEAD~1 - производит откат на HEAD-коммит ветки, в случае если ненужные изменения уже были закоммичены. git reset HEAD^ - производит откат на HEAD^-коммит ветки, при этом все файлы, которые были в коммитах после этого HEAD^, становятся модифицированными и при этом все изменения, которые были, остаются.

Отмена индексации файла

git reset - отменяет индексирование всех файлов. git reset <файл> - отменяет индексирование файла. git reset HEAD <файл> - отменяет индексацию файла.

Отмена изменений файла

git checkout -- <файл> - отменяет изменения файла, возвращает то состояние, в котором он находился во время последнего коммита (или первоначального клонирования, или какого-то другого действия, после которого файл попал в рабочий каталог). Все сделанные изменения в этом файле пропадают - просто происходит копирование поверх него другого файла. git checkout <коммит> -- <файл> - производит откат файла на коммит ветки.

Скрытие (stashing) изменений до коммита

git stash - временно скрывает внесенные изменения и оставляет чистую рабочую копию. Теперь можно переключиться на другую ветку для внесения срочных изменений, не оформляя уже сделанные изменения как коммиты. git stash pop - возвращает скрытую функциональность. git stash drop [<stash>] - удаляет скрытую функциональность. git stash list - выводит список спрятанного. git stash show [-p] <stash> - показывает то, что скрыто в виде статиски по файлам [в виде их отличий]. git stash apply <stash> - применяет скрытую функциональность.

Очистка рабочей директории

git clean - предназначена для удаления неотслеживаемых файлов из рабочей директории, будет удалять только неотслеживаемые файлы, которые не добавлены в список игнорируемых. git clean -d -f - удалит все файлы и также все директории из-за ключа -d, которые в результате станут пустыми. Опция -f значит force или другими словами "действительно выполнить это". git clean -d -n - выведет список того что нужно удалить.

Ключ -x - удалит все файлы, которые в .gitignore.

Перемещение по коммитам

git checkout <имя_коммита> - переходит на существующий коммит, т.е. это действие передвинет HEAD так, чтобы тот указывал на указанный коммит. git checkout <имя_коммита>^[<номер_родителя_ветки>] - переходит на коммит назад, т.е. это действие передвинет HEAD так, чтобы тот указывал на предыдущий коммит. git checkout <имя_коммита>~<num> - переходит на <num> коммитов назад, т.е. это действие передвинет HEAD так, чтобы тот указывал на <num> предыдущих коммитов. С HEAD можно использовать как относительную ссылку и работать как с коммитом.

Ветвление в Git

Ветка в Git'е - это просто легковесный подвижный указатель на один из цепочки коммитов. Ветка по умолчанию в Git'е называется master.

git branch <имя_ветки> - создает новую ветку, т.е. эта команда создаст новый указатель на тот самый коммит, который сейчас активен. Не переключает на созданную ветку. Git хранит специальный указатель, который называется HEAD (верхушка), это указатель на локальную ветку, которая сейчас активна. git checkout <имя_ветки> - переходит на существующую ветку, т.е. это действие передвинет HEAD так, чтобы тот указывал на указанную ветку:

  • ключ -b - позволяет создать новую ветку и сразу перейти на вновь созданную ветку.

git checkout - - переходит на предыдущую ветку.

git checkout <имя_ветки>^ - переходит на существующую ветку на коммит назад, т.е. это действие передвинет HEAD так, чтобы тот указывал на предыдущий коммит указанной ветки. git checkout <имя_ветки>~<num> - переходит на существующую ветку на <num> коммитов назад, т.е. это действие передвинет HEAD так, чтобы тот указывал на <num> предыдущих коммитов указанной ветки. git branch -f <имя_ветки> <коммит> - прикрепляет ветку к указанному коммиту, производит форсинг. git reset HEAD{^ | ~<num>} - откатывает ветку до указанного коммита. git revert <коммит> - создавая новый коммит, который просто содержит изменения, полностью противоположные тем, что сделаны в указанном коммите. git branch -m [<старое_имя_ветки>] <имя_ветки> - переименовывает ветку. git branch -u <имя_удал_репоз>/<ветка> - настраивает отслеживание текущей ветки на удаленную ветку.

git reset --hard <имя_удал_репоз>/<ветка> - синхронизирует текущую ветку с удаленной веткой.

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

Основы ветвления и слияния

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

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

git merge <имя_ветки> - сливает указанную ветку с текущей веткой.

Если происходит попытка слить один коммит с другим таким, которого можно достигнуть, проследовав по истории первого коммита, Git поступает проще, перемещая указатель вперед, так как нет расходящихся изменений, которые нужно было бы сливать воедино. Это называется "перемотка" (fast forward). Иначе Git создает новый снимок состояния, который является результатом трехходового слияния, и автоматически создает новый коммит, который указывает на этот новый снимок состояния. Такой коммит называют коммит-слияние, так как он является особенным из-за того, что имеет больше одного предка. Для обязательного создания коммита слияния используется опция: --no-ff.

Опции:

  • --no-commit - позволяется слить ветку без закрывания коммита мерджа при удачном слиянии;
  • -X theirs - стратегия при сливании ветки, при решении конфликта применяет все изменения из сливающей <имя_ветки>;
  • -X ours - стратегия при сливании ветки, при решении конфликта применяет все изменения из текущей;
  • -Xignore-space-change - позволяет при слиянии игнорировать изменение пробельных символов и символов окончания строк.

git merge --no-commit --squash <ветка> - позволяет слить только файлы из ветке в текущую ветку без закрывания коммита.

git merge --abort / git reset --merge - отменяет текущее слияние.

git cherry-pick <коммит1> [<коммит2> [ ...]] - копирует изменения указанных коммитов в текущую ветку. git branch -d <имя_ветки> - удаляет указанную ветку.

  • с помощью опции -D можно удалить даже ту ветку, которая еще не слита не с одной.

git push <имя_удал_сервера> --delete <имя_ветки> - удаляет указанную ветку на удаленном сервере.

git checkout <имя_ветки> -- <имя_файла> - копирует файл из указаной ветки в текущую.

Основы конфликтов при слиянии

Если было изменено одна и та же часть файла по-разному в двух ветках, которые будут сливаться, Git не сможет сделать это чисто, то получится конфликт слияния. Git не создаст новый коммит для слияния. Он приостановит этот процесс до тех пор, пока не разрешится конфликт. Если нужно посмотреть, какие файлы не прошли слияние (на любом этапе после возникновения конфликта), выполнится команда git status. Все, что имеет отношение к конфликту слияния и что не было разрешено, отмечено как unmerged.

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

В верхней части блока (все что после <<<<<<< HEAD:<имя_файла> и до =======) это версия из HEAD (текущей ветки, так как именно на нее был произведен переход перед выполнением команды merge), все, что находится в нижней части и до >>>>>>> <имя_ветки>:<имя_файла> - версия из другой ветки. Чтобы разрешить конфликт, необходимо либо выбрать одну из этих частей, либо как-то объединить содержимое по своему усмотрению.

После того как были устранены конфликты с каждой из таких секций в каждом из конфликтных файлов, выполняется git add для каждого конфликтного файла. Индексирование будет означать для Git'а, что все конфликты в файле теперь разрешены.

Можно использовать графические инструменты для разрешения конфликтов, с помощью выполнения команды git mergetool, которая запустит соответствующий графический инструмент и покажет конфликтные ситуации. После того как был произведен выход из инструмента для выполнения слияния, Git спросит, было ли оно успешным. Если ответ да - файл индексируется (добавляется в область для коммита), чтобы дать понять, что конфликт разрешен.

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

Управление ветками

git branch - возвращает список имеющихся веток. Символ *, стоящий перед именем ветки: указывает на ветку, которая активна в настоящий момент. git branch -v - выводит последний коммит на каждой из веток. git branch -r - выводит список всех веток в удаленном репозитории. git branch --sort=-committerdate - выводит список всех веток в сортировке по дате последнего коммита.

Опции отображения:

  • --merged и --no-merged - оставляют в списке только те ветки, которые были слили (или не слили) в ветку, которая активна сейчас;
  • --contains <коммит> и --no-contains <коммит> - оставляют в списке только те ветки, которые содержат указанный коммит (или не содержат его).

git cherry -v <имя_ветки1> <имя_ветки2> - показывает коммиты, которые есть в ветке <имя_ветки2>, но не в ветке <имя_ветки1>.

Приемы работы с ветками

Долгоживущие ветки

В Git'е придерживаются такого подхода, при котором ветка master содержит исключительно стабильный код - единственный выпускаемый код. Для разработки и тестирования используется параллельная ветка, называемая develop или next, она может не быть стабильной постоянно, но в стабильные моменты ее можно слить в master. Эта ветка используется для объединения завершенных задач из тематических веток, чтобы удостовериться, что эти изменения проходят все тесты и не вызывают ошибок.

Некоторые большие проекты также имеют ветку proposed или pu (proposed updates - предлагаемые изменения), которые включают в себя ветки, не готовые для перехода в ветку next или master. Идея такова, что ветки находятся на разных уровнях стабильности; когда они достигают более высокого уровня стабильности, они сливаются с веткой, стоящей на более высоком уровне.

Тематические ветки

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

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

Удаленные ветки

Удаленные ветки - это ссылки на состояние веток в удаленных репозиториях. Это локальные ветки, которые нельзя перемещать; они двигаются автоматически всякий раз, когда осуществляется связь по сети. Удаленные ветки действуют как закладки для напоминания о том, где ветки в удаленных репозиториях находились во время последнего подключения к ним.

Они выглядят как (<имя_удал_репоз>)/(<ветка>).

Клонирование Git-проекта дает собственную ветку master и origin/master, указывающий на ветку master в удаленном репозитории origin.

До тех пор, пока не будет связи с сервером origin, ваш указатель origin/master не будет сдвигаться. Ветка master на сервером origin может в это время измениться.

Для синхронизации работы выполняется команда git fetch origin. Эта команда ищет, какому серверу соответствует origin; извлекает оттуда все данные, которых еще нет, и обновляет локальное хранилище данных; сдвигает указатель origin/master на новую позицию.

git push <имя_удал_репоз> <ветка>[:<новое_имя>] - отправляет (push) ветку на удаленный сервер, на котором есть права на запись, вместо <ветка> можно использовать HEAD, который будет синонимом <ветка>. Флаг -u обозначает связывание с удаленной веткой что позволяет тогда находясь на ветке выполнять git push без указания конкретики.

git push <имя_удал_репоз> <ветка_локальная>:<ветка_удаленная> - отправляет (push) ветку локальную <ветка_локальная> на удаленный сервер в ветку <ветка_удаленная> без переключения на ветку <ветка_локальная>.

Когда кто-то будет получать обновления с сервера, он получит ссылку на то, на что указывает <ветка> на сервере, как удаленную ветку origin/<ветка>.

git pull <имя_удал_репоз> <ветка_удаленная> - получает (pull) все изменения из ветки <ветка_удаленная> в локальную ветку.

git pull --rebase <имя_удал_репоз> <ветка_удаленная> - получает (pull) все изменения из ветки <ветка_удаленная> в локальную ветку с использованием перемещения.

Важно, что когда при получении данных появляются новые удаленные ветки, то автоматически не получаются для них локальные редактируемые копии. Для этого необходимо слить эти наработки в текущую рабочую ветку, с помощью команды git merge origin/<ветка>. Это даст локальную ветку, на которой можно работать. Она будет начинаться там же, где и origin/<ветка>.

Отслеживание веток

Получение локальной ветки с помощью git checkout из удаленной ветки автоматически создает отслеживаемую ветку - это локальная ветка, которая напрямую связана с удаленной веткой.

Если, находясь на отслеживаемой ветке, набрать git push, Git уже будет знать, на какой сервер и в какую ветку отправлять изменения. Аналогично выполнение git pull на одной из таких веток сначала получает все удаленные ссылки, а затем автоматически делает слияние с соответствующей удаленной веткой.

При клонировании репозитория, как правило, автоматически создается ветка master, которая отслеживает origin/master.

git checkout -b <ветка> <имя_удал_репоз>/<ветка> - настраивает отслеживание ветки из удаленного репозитория.

Удаление веток на удаленном сервере

git push <имя_удал_репоз> :<ветка> - удаляет (push) ветку на удаленном сервере, на котором есть права на запись.

Просмотр информации удаленного репозитория

git remote show <имя_удал_репоз> - выдает URL удаленного репозитория, а также информацию об отслеживаемых ветках. git remote -v - отображает адреса на отправку и получение данных от репозиториев.

Перемещение по веткам

git rebase <ветка> - берет все изменения, которые попали в коммиты на текущей ветке, и повторяет их на указанной ветке (последовательно берет все коммиты из выбранной ветки и заново применяет их к новой ветке). Работает следующим образом: находится общий предок для двух веток; для каждого из коммитов в текущей ветке берется его дельта и сохраняется во временный файл; текущая ветка устанавливается на тот же коммит, что и ветка, на которую выполняется перемещение; и, наконец, одно за другим применяются все изменения. Переприменяя коммиты, git создает новые. Эти новые коммиты, даже если они вносят тот же набор изменений, будут рассматриваться git-ом как совершенно разные и независимые.

На этом этапе можно переключиться на ветку <ветка> и выполнить слияние-перемотку (fast-forward merge), т.е. перейти к последнему коммиту. Это делается путем слияния из <ветка> с текущей веткой.

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

git rebase --onto <ветка_результирующая> <ветка_исключающая> <ветка_из> - берет изменения из ветки <ветка_из>, которых нет в <ветка_исключающая>, и применить их на ветке <ветка_результирующая>. Это указание "переключиться на ветку <ветка_из>, взять изменения от общего предка веток <ветка_из> и <ветка_исключающая> и повторить их на <ветка_результирующая>".

                                        master     client
                                          |           |
                                          v           v
+----+    +----+    +----+    +----+    +-----+    +-----+
| C1 |<---| C2 |<---| C5 |<---| C6 |<---| C8' |<---| C8' |
+----+    +----+    +----+    +----+    +-----+    +-----+
            ^
            |       +----+    +----+    +-----+
            +-------| C3 |<---| C4 |<---| C10 |
                    +----+    +----+    +-----+
                      ^                   ^
                      |                   |
                      |                 server
                      |
                      |       +----+    +----+
                      +-------| C8 |<---| C9 |
                              +----+    +----+

Теперь можно выполнить перемотку (fast-forward) для ветки <ветка_результирующая>.

git rebase <ветка_результирующая> <ветка> - устанавливает тематическую ветку <ветка> как текущую и применяет ее изменения на основной ветке - <ветка_результирующая>.

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

git rebase -i HEAD~<num> - позволяет в визуальном редакторе выбрать нужные коммиты и их порядок следования из списка из <num> коммитов для нового ответвления для текущей ветки.

git rebase --interactive <ветка> - после выполнения команды откроется текстовый редактор, в котором необходимо ввести команды, что нужно делать с коммитами из текущей ветки в ветку <ветка>.

Возможные риски перемещения заключаются в том что: не перемещаются коммиты, которые уже отправлены в публичный репозиторий.

Git на сервере

Удаленный репозиторий - это голый (чистый, bare) репозиторий - Git-репозиторий, не имеющий рабочего каталога. Этот репозиторий используется только для обмена и он содержит только данные Git'а. Голый репозиторий содержит только каталог .git проекта и ничего больше.

Протоколы

Локальный протокол

Локальный протокол - это удаленный репозиторий - другой каталог на диске.

git clone [file://]/<путь_к_проекту>.git [<имя_результирующего_каталога>] - клонирует репозиторий. git remote add <сокращение> [file://]/<путь_к_проекту>.git - добавляет локальный репозиторий в существующий проект.

Протокол SSH

Протокол SSH - единственный из сетевых протоколов, предоставляющий доступ и на чтение, и на запись. SSH это протокол с аутентификацией.

git clone ssh://<user>@<server>/<путь_к_проекту>.git - клонирует репозиторий. git clone <user>@<server>:<путь_к_проекту>.git

ssh -T <user>@<server> - используется для проверки доступа к серверу.

Git-протокол

Git-протокол - специальный демон, который слушает порт 9418 и предоставляет сервис, схожий с протоколом ssh, но абсолютно без аутентификации. Чтобы использовать Git-протокол для репозитория, нужно создать файл git-daemon-export-ok, иначе демон не будет работать с этим репозиторием. В протоколе отсутствуют средства безопасности.

Протокол HTTP/S

Все, что необходимо сделать для использования - это поместить голый репозиторий внутрь каталога с HTTP документами, установить перехватчик post-update.

Перехватчик post-update, входящий в состав Git'а по умолчанию, выполняет необходимую команду (git update-server-info), чтобы извлечение (fetch) и клонирование (clone) по HTTP работали правильно. Эта команда выполняется, когда отправляются изменения в репозиторий по SSH.

Настройка Git на сервере

Для того чтобы осуществить первоначальную настройку любого Git-сервера, необходимо экспортировать существующий репозиторий в новый "голый" репозиторий, т.е. репозиторий без рабочего каталога.

Чтобы склонировать репозиторий и создать новый "голый" репозиторий, необходимо выполнить команду clone с параметром --bare. По существующему соглашению, каталоги с голыми репозиториями заканчиваются на .git.

git clone --bare <проект> <голый_проект>.git - создает новый "голый" репозиторий. scp -r <голый_проект>.git <user>@<server>:<путь_к_проекту>.git - размещает "голый" репозиторий на сервере.

Полезные команды

  • Сбор всех файлов ветки в архив:

git diff --name-status master | tr \' \" | awk '{ if ($1 != D && $2 !~ /\"/) print $2 }' > list.txt ; tar -cvf release.tar.gz -T list.txt ; rm list.txt

  • Вывод всех комитов и их файлов, которые есть только в указанной ветке, но не в другой:

git log master..<ветка> --pretty=format:"%H" --name-only

  • Вывод всех файлов:

Вывод всех файлов, которые были изменены в коммитах с сообщением, которое содержит ELK-906 в 100 предыдущих коммитах.

COMMITS="$(git log -100 --stat | grep ELK-906 -B 5 | grep commit | sed 's/commit //g' | paste -sd " " -)"; git show ${COMMITS} --pretty=format:"" --name-only | sed '/^$/d' | sort | uniq

  • Обновление текущей ветки мастером:

BRANCH="$(git branch | grep "*" | sed 's/* //g')"; git stash && git checkout master && git fetch && git pull origin master && git checkout ${BRANCH} && git merge master -Xignore-space-change && git stash pop

  • Вывод последних коммитов всех веток:

git for-each-ref --format="%(committerdate) %09 %(objectname) %09 %(refname)" --sort=-committerdate refs/heads/

  • Вывод измененных строк в измененных файлах в которых есть строка:

for FILE in $(git diff --name-only); do echo -e "filename: \e[32m$FILE\e[39m"; git diff $FILE | grep -E "^\\+ " | grep --colour "\.log("; echo ""; done

  • Выводит граф коммитов:

git log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all

  • Скрипт по полному обновлению всех веток всех репозиториев внутри текущего каталога скрипта:
#!/bin/bash
ARR=$(find -type d -name \.git -exec echo {} \; | sed 's/\/\.git//');
DIR=$(pwd);
echo -e "\e[32mcurrent folder: ${DIR}\e[39m";
for FOLDER in $ARR;
do
 echo -e "\e[32mupdate folder: ${FOLDER}\e[39m";
 cd $FOLDER;
 git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done; git fetch --all && git pull --all;
 cd $DIR;
done;