Взаимодействие с git
Хотя для git есть дикое количество графических интерфейсов, в его основе лежит консольная утилита, тонкими обёртками к которой вышеупомянутые графические интерфейсы являются.
Поэтому здесь мы обсудим именно процесс работы с консольной утилитой (который весьма специфичен по сравнению, например, с таковым для системы контроля версий гуглодокументов или же некоторых сред разработки; причём вся эта специфичность сохраняется и при работе с графическими интерфейсами).
Самое главное
Если хочется узнать что-то поподробнее, git help
Вам в помощь. Также
им рекомендуется пользоваться во всех непонятных ситуациях.
Начало работы
Для того, чтобы объявить текущую папку «git-репозиторием»
(проще говоря — отдать под управление git), можно воспользоваться
командой git init
, находясь в этой папке.
Также можно создать новую папку под управлением git командой git init название_папки
или же создать т.н. «голый» репозиторий командой git init название_папки --bare
. Зачем нужен последний — см. соответствующий подраздел.
Два основных этапа работы
Содержимое git-репозитория называется Working Tree. Для того, чтобы сохранить состояние Working Tree в истории репозитория, нужно сделать две вещи:
- пометить командой
git add
те файлы, изменения в которых следует сохранить - подтвердить сохранение изменений командой
git commit
Для простоты первый шаг можно делать командой git add -A
, которая помечает
все изменения во всех файлах Working Tree (в том числе — новые файлы и
удалённые файлы).
На втором шаге команда git commit
вызывает некоторый текстовый редактор,
в котором предлагается кратко описать суть произведённых изменений.
Этот файл нужно сохранить и закрыть текстовый редактор. Если Вам вызванный
git-ом текстовый редактор не нравится, можно либо перенастроить git
(см. git help config
), либо же пользоваться
командой git commmit -m краткое_описание
.
В заключение скажем, что если хочется игнорировать некоторые файлы,
находящиеся в Working Tree, их можно прописать в файл
с названием .gitignore
, который следует поместить в ту папку, внутри которой
(в том числе — в её подпапках, подпапках подпапок и т.д.) лежат
эти самые игнорируемые файлы.
Ветки
Самая неочевидная часть git — т.н. «ветки».
А именно, история версий может быть нелинейной: вернувшись к одной из предыдущих версий, можно на неё накатить какие-то изменения, при этом получив новое ответвление истории и сохранив все версии оригинальной истории.
Также можно соединить воедино два разных ответвления, получив версию, в которой отражены как изменения одного ответвления, так и другого.
Вышеупомянутая же неочевидность связана с очень неудачной терминологией, которую git использует: термином Branch названо не ответвление истории, как можно было бы предположить, а просто имя для какой-нибудь версии.
Для работы с Branch используются в основном три комадны:
git branch
— для создания новых веток и печати имеющихсяgit checkout
— для перехода к какой-то ветке или какой-то версииgit merge
— для слияния текущей ветки с какой-нибудь другой
Для того, чтобы объяснить, как эти команды работают, введём ещё один термин: словом HEAD называется та версия, в которой «мы сейчас находимся».
При этом голова (т.е. HEAD) может быть в одном из двух состояний:
- привязана к какой-то ветке
- привязана к какой-то версии, но не к ветке (такое состояние называется detached)
Состояние, в котором находится HEAD, влияет на поведение команды
git commit
:
- если голова привязана к ветке, то эта ветка (напомним ещё раз, что ветка — это просто название для версии, а не путь в графе) переходит на свежесозданную версию
- если голова привязана к версии, то никакие ветки никуда не двигаются
Изначально в свежесозданном репозитории есть ровно одна ветка (обычно
с названием master
или main
), к которой привязана голова.
Для того, чтобы привязать голову к какой-то версии, нужно выполнить
команду git checkout
с идентификатором этой версии в качестве аргумента
(идентификаторы можно посмотреть командой git log
).
Для того, чтобы привязать голову к какой-то ветке, нужно либо выполнить
команду git checkout
с этой самой веткой (напомним в третий раз, что ветка
— это всего лишь название для версии) в качестве аргумента, либо
выполнить команду git branch новая_ветка
.
Слияние веток и работа с удалёнными репозиториями
Иногда ответвления истории образуются как некоторые независимые друг от друга нити работы над проектом (например, один человек изменяет одну часть, другой — другую).
В такой ситуации ответвления приходится в некоторый момент соединять. Причём зачастую эти ответвления находятся в разных репозиториях, склонированных из какого-то одного общего.
Один репозиторий
Если ответвления находятся в одном репозитории, то всё весьма просто:
- переходим в одну из веток
- делаем
git merge другая_ветка
- если всё ок, то на этом всё заканчивается
- если же возникли какие-то конфликты, которые не удаётся исправить
встроенными в git эвристиками, исправляем их вручную и делаем
git commit
Настоятельно рекомендуется хотя бы раз попробовать вызвать нетривиальный конфликт и посмотреть, как именно git обозначает этот конфликт внутри соответствующего файла, чтобы потом это не стало неприятным сюрпризом.
Несколько репозиториев
Любой репозиторий (хоть — находящийся на том же компьютере, но
в другой папке, хоть — находящийся на другом компьютере)
можно склонировать командой git clone
, аргументом которой должен
быть путь к репозиторию. Обычно этот путь — одно из трёх:
- относительный или абсолютный путь папки на том же компьютере
- если другой компьютер доступен по ssh — имя другого компьютера
(такое, как настроено в
.ssh/config
), за которым следует двоеточие, за которым следует имя папки на другом компьютере - для сервисов типа github — просто обычный интернет-локатор наподобие
https://github.com/foobar/baz
Склонированный репозиторий называется удалённым (remote, а не deleted, как можно было бы подумать) по отношению к его клону. Внутри репозитория-клона становятся доступными новые команды:
git push
— перенести текущую ветку (со всеми необходимыми версиями) на удалённый репозиторий и слить там с одноимённой веткойgit pull
— перенести одноимённую с текущей ветку с удалённого репозитория в локальный и слить там с текущей
Голые репозитории
Некоторую проблему представляет git push
в ту ветку, которая на удалённом
репозитории является текущей. С этим можно бороться двумя способами:
- не делать
git push
в текущую для удалённого репозитория ветку - сделать удалённый репозиторий вообще без Working Tree (т.н. bare-репозиторий)
Второй подход настоятельно рекомендуется применять для основного репозитория проекта, с которого все, кто над проектом работает, делают клоны.
Для реализации этого самого второго подхода достаточно создать репозиторий
с опцией --bare
. Собственно, всевозможные коллаборационные сервисы типа
github как раз создают на своих серверах репозиторий именно такого типа.