Взято здесь.
Путь проекта: от идеи до GitHub за 5 шагов
Итак, у нас есть папка с проектом на компьютере. Мы хотим начать вести его историю с помощью Git, а потом выгрузить на GitHub. Что делать?
Шаг 1. Инициализируем репозиторий
Первым делом нужно сказать Git, чтобы он начал следить за папкой. Для этого открываем терминал в папке проекта и пишем:
git init
Эта команда создаст внутри скрытую папку .git. Именно в ней Git будет хранить всю историю изменений. Поздравляем, теперь эта папка — полноценный локальный репозиторий.
Шаг 2. Добавляем файлы под версионный контроль
Теперь укажем, какие именно файлы мы будем отслеживать. Например, мы создали index.html и style.css. Чтобы подготовить их к коммиту, используем команду git add.
Можно добавлять файлы по одному:git add index.html
А можно добавить сразу все изменённые файлы в папке:git add
Эта команда помещает файлы в так называемую «область подготовки» (staging area). Будто мы ходим по супермаркету и складываем продукты в тележку, а не тащим всё в руках, перед тем, как подойти на кассу. Мы решаем, что именно попадёт в следующий коммит.
Шаг 3. Фиксируем изменения (тот самый коммит)
Вот мы добавили всё нужное. Пора делать коммит — «снимок» состояния. У каждого коммита должно быть осмысленное сообщение, чтобы потом мы или коллеги поняли, что именно было сделано.
git commit -m "Первый коммит: создана структура проекта"
Ключ -m как раз позволяет написать сообщение прямо в команде. Стараемся писать понятно и по делу, избегая сообщений вроде «фикс», «обновление» или «123». Да, это чуть быстрее, но на долгой дистанции сыграет не на пользу. Подробные сообщения помогают сохранить контекст изменений, упрощают понимание истории проекта остальными членами команды и облегчают отладку.
Шаг 4. Привязываем к удалённому репозиторию
Сейчас репозиторий живёт только на нашем компьютере. Чтобы им можно было поделиться или сделать резервную копию, его нужно связать с удалённым репозиторием, например, на GitHub.
Для этого создаём пустой репозиторий на сайте, а потом выполняем в терминале команду:
git remote add origin https://github.com/твой_ник/твой_репозиторий.git
Эта команда говорит: «Дорогой Git, по этому адресу будет жить удалённая версия нашего репозитория, а звать её будем origin». Это стандартное имя для основного удалённого репозитория.
Шаг 5. Отправляем изменения на GitHub
Теперь можем отправлять коммиты в «облако». Делаем это командой push. В первый раз она выглядит чуть длиннее:
git push -u origin main
Разберём:
- push — команда «отправить».
- origin — куда отправляем (то имя, что мы задали на шаге 4).
- main — какую ветку отправляем (main — обычно основная ветка в проекте).
- -u — этот флаг создаёт связь между локальной и удалённой веткой. Благодаря ему в следующий раз достаточно будет написать просто git push.
При первом пуше GitHub попросит авторизоваться.
Важный момент: сейчас вместо пароля от аккаунта нужно использовать специальный токен доступа — personal access token, который создаётся в настройках GitHub. Это безопаснее. Сохраним его в надёжном месте, он нам ещё пригодится.
Вот мы и прошли полный цикл: создали репозиторий, сделали первый коммит и отправили работу на GitHub.
С базовыми командами разобрались, теперь пойдём к одной из самых важных идей в Git — к веткам.
Как работать над задачами и ничего не сломать
До сих пор мы работали в одной-единственной ветке, которую по умолчанию назвали main (или master в старых проектах). Это «чистовая» версия проекта.
Но что делать, если нас вдруг посетило вдохновение и мы захотели добавить новую фичу, исправить баг или просто поэкспериментировать с кодом. Делать это прямо в main сомнительная идея — можно всё сломать.
И вот тут нам пригодятся ветки.
Зачем нужны ветки
Ветку можно создать в любой момент — и это будет точная копия основной ветки.
После этого мы можем делать в ней что угодно: писать новый код, удалять старый, пробовать какие-то крейзи-идеи — и всё это никак не затронет стабильную версию в ветке main.
Вообще, ветки — это основа безопасной и совместной работы в Git. Каждый разработчик создаёт отдельную ветку для своей задачи, спокойно работает в ней, а когда всё готово — «вливает» свои изменения в общую.
Создаём и переключаемся между ветками
Немного потренируемся.
Вот хотим мы добавить на сайт шапку. Создаём для этой задачи отдельную ветку с говорящим названием, например, feature/header.
Чтобы создать новую ветку, используем команду git branch:
git branch feature/header
Ветка создана, но мы всё ещё находимся в main. Чтобы перейти в новую ветку и начать в ней работать, нужна команда git checkout:
git checkout feature/header
Теперь мы находимся в своей личной «песочнице». Все коммиты, которые мы будем делать, сохранятся только в истории ветки feature/header и не повлияют на main.
Эти две команды можно объединить в одну, чтобы было быстрее:
git checkout -b feature/header
Эта команда сразу и создаст новую ветку, и переключит нас на неё. Флаг -b — это сокращение от branch.
Золотое правило Git — всегда создавайте новую ветку для каждой новой задачи. Даже чтобы исправить опечатку.
Это помогает:
- содержать репозиторий в чистоте и порядке;
- не смешивать в одном коммите изменения из разных задач;
- делать код-ревью (проверку кода другими членами команды) — без веток это было бы невозможно;
- защитить основную ветку от случайных ошибок и недоделанного функционала.
Когда работа над задачей в ветке закончена и её изменения успешно слиты с main (об этом поговорим в следующем разделе), эту ветку можно и нужно удалить. Иначе она будет мешаться. Делаем это командой git branch с флагом -d (от delete):
git branch -d feature/header
Мы создали отдельную ветку, поработали в ней, сделали несколько коммитов, и теперь наша новая фича полностью готова. Пришло время объединить нашу работу с основной веткой main. Этот процесс называется слиянием или мёрджем.
Мёрджим
Слияние — это процесс переноса изменений (коммитов) из одной ветки в другую. В нашем случае мы хотим перенести всё, что сделали в ветке feature/header, в ветку main.
Делаем так:
- Переключаемся на целевую ветку. Сначала нужно перейти в ту ветку, с которой мы хотим объединить изменения. В нашем случае это main.
git checkout main - Обновляем основную ветку. Перед слиянием всегда полезно убедиться, что локальная ветка main содержит самые свежие изменения из удалённого репозитория (вдруг кто-то из коллег уже что-то туда добавил).
git pull origin main - Выполняем слияние. Теперь в ветке main выполняем команду git merge и указываем имя ветки, из которой мы хотим забрать изменения.
git merge feature/header
После этой команды Git попытается автоматически объединить истории двух веток. Он возьмёт все коммиты из feature/header, которых нет в main, и добавит их в неё.
Что такое коммит слияния
Чаще всего Git создаёт специальный коммит слияния (merge commit). Это коммит, у которого есть сразу два родителя — последний коммит в main до слияния и последний коммит в твоей рабочей ветке. Он наглядно показывает в истории, в какой момент произошло объединение веток.
Иногда, если с момента создания ветки feature/header в main не появилось новых коммитов, Git может выполнить так называемое «ускоренное слияние» (fast-forward). В этом случае он просто передвинет указатель ветки main на последний коммит из feature/header, не создавая отдельного коммита слияния.
Что делать с конфликтами
Иногда Git не может автоматически объединить ветки. Это происходит, если в обеих ветках были изменены одни и те же строки в одном и том же файле. Такая ситуация называется конфликтом слияния.
Git не знает, какую версию кода считать правильной, поэтому он останавливает слияние и просит нас решить этот конфликт ручками.
Он помечает конфликтующие места в файлах специальными маркерами — <<<<<<<, =======, >>>>>>>.
Наша задача — открыть эти файлы, посмотреть на изменения из обеих веток, решить, какой код оставить (или написать новый вариант), удалить маркеры Git и сохранить файлы.
Когда все конфликты будут решены, нужно будет снова добавить исправленные файлы командой git add . и завершить слияние, создав коммит: git commit. Git сам подставит стандартное сообщение о слиянии.
Разрешение конфликтов — это нормальная часть рабочего процесса, так что не боимся её.
Проверяем историю и состояние
УGit есть простые команды, чтобы в любой момент разобраться в происходящем.
git status
Если бы нужно было выбрать только одну команду, которую стоит выучить, это была бы git status.
Используем её постоянно: перед коммитом, после слияния, когда хотим понять, что происходит в репозитории. Она ничего не меняет — только показывает состояние рабочего каталога и раздела проиндексированных файлов. Проще говоря, она отвечает на три вопроса:
- Какие файлы изменены, но ещё не подготовлены к коммиту? (Changes not staged for commit). Это файлы, которые мы поменяли, но ещё не добавили в «корзину» через
git add. - Какие файлы готовы к коммиту? (Changes to be committed). Это то, что мы уже добавили через
git addи что попадёт в следующий коммит. - Какие файлы Git ещё не отслеживает? (Untracked files). Это новые файлы в проекте, о которых Git пока ничего не знает.
git log
Команда git log позволяет заглянуть в историю проекта и посмотреть список сделанных коммитов. В базовом виде она показывает автора, дату и сообщение для каждого коммита.
У неё есть много других полезных опций, которые делают вывод гораздо удобнее:
- git log –oneline: показывает каждый коммит в одну строку: только хеш (уникальный идентификатор) и сообщение. Подходит для быстрого обзора истории.
- git log –graph: Рисует текстовое «дерево», которое показывает, как ветки создавались, расходились и сливались обратно.
- git log -p: Показывает не только информацию о коммитах, но и сами изменения в каждом из них. Удобно, чтобы найти, когда и где была добавлена конкретная строка кода.
Часто эти флаги комбинируют, например, git log --oneline --graph --all покажет краткую историю всех веток в виде наглядного дерева.
git diff
Команда git diff позволяет увидеть разницу между разными состояниями файлов. Иногда (всегда) полезно перед коммитом ещё раз проверить, какие именно изменения мы собираемся сохранить.
- git diff: Показывает разницу между тем, что у нас сейчас в рабочих файлах, и тем, что было в последнем коммите. Мы увидим все изменения, которые ещё не были добавлены через git add.
- git diff –staged (или –cached): Показывает изменения, которые мы уже подготовили к коммиту (добавили через git add), в сравнении с последним коммитом. Это наш шанс проверить, не добавили ли мы в коммит чего-то лишнего.
Как отменять и исправлять ошибки
Даже самые опытные разработчики иногда коммитят не те файлы. Прелесть Git в том, что почти всё можно исправить.
Сценарий 1: «Мы сделали коммит, но забыли добавить файл или опечатались в сообщении»
Это, пожалуй, самая частая ситуация. Мы только что нажали Enter, и тут же поняли, что в коммит не вошёл один маленький файл. Или в сообщении написано «фикс бага» вместо «исправлена опечатка на главной». Но это не беда.
Для этого есть команда git commit –amend (это «внести поправку» на английском). Она позволяет «дополнить» самый последний коммит.
- Если мы забыли добавить файл, просто сделаем это сейчас через git add забытый_файл.js.
- Выполняем команду: git commit –amend.
И сразу откроется редактор, где мы сможем поправить сообщение коммита. Если мы просто хотели добавить файл, можем ничего не менять и сразу закрыть редактор. Git возьмёт новые изменения из git add, объединит их с предыдущим коммитом и создаст один исправленный коммит вместо старого.
Важно: используем git commit –amend только для тех коммитов, которые ещё не были отправлены на удалённый сервер (git push).
Сценарий 2: «Мы случайно добавили лишний файл в “корзину”»
Мы готовим коммит, пишем git add ., и внезапно понимаем, что в область подготовки улетел временный файл или что-то, что коммитить ещё рано.
Чтобы убрать файл из области подготовки, но оставить его изменения в рабочей папке, используем команду git reset:
git reset HEAD <имя_лишнего_файла>
Команда git status после этого покажет, что файл снова находится в разделе «Changes not staged for commit».
Сценарий 3: «Мы хотим отменить все изменения в файле и вернуть его к последней сохранённой версии»
Мы что-то меняли в файле, поняли, что всё пошло не так, и хотим просто вернуть его к состоянию последнего коммита, как будто мы его и не открывали.
git checkout -- <имя_файла>
Но будем осторожны — эта команда безвозвратно удаляет все несохранённые локальные изменения в файле. Git даже не спросит подтверждения. Используем её, только если мы на 100% уверены, что хотим стереть свою работу.
Сценарий 4: «Мы отправили коммит на GitHub, и с ужасом поняли, что он всё ломает»
Это более серьёзная ситуация. Коммит уже попал в общую историю, и, возможно, наши коллеги уже успели его скачать. Просто удалить или переписать его, как это делает reset, очень плохая идея — это вызовет хаос и конфликты у всей команды.
Для безопасной отмены публичных коммитов есть команда git revert.
git revert <хеш_плохого_коммита>
Она не удаляет старый коммит. А создаёт новый, который делает ровно противоположные изменения. Если в плохом коммите мы добавили строку, revert-коммит её удалит. История проекта остаётся чистой и последовательной, а все члены команды легко смогут синхронизировать свои репозитории.
Сценарий 5: «Мы сделали несколько плохих коммитов локально и хотим их просто удалить»
Мы работали в своей ветке, сделали 3 коммита и поняли, что пошли не в ту сторону. Эти коммиты ещё никто не видел — мы не делали push. В этом случае можно использовать git reset, чтобы «перемотать» историю назад, как будто этих коммитов и не было.
git reset --hard HEAD~3
Эта команда удалит последние 3 коммита и вернёт состояние всех файлов к моменту до них. HEAD~3 означает «на 3 коммита назад от текущего».
Очень важно:
git reset --hard— мощная и разрушительная команда. Она переписывает историю и стирает изменения. Используем её только для локальных коммитов, которые ещё не были отправлены в общий репозиторий.
Более сложные и мощные инструменты
git stash
Однажды я работала над новой фичей в своей ветке, код был в полуразобранном состоянии, к коммиту готово ровно ноль. И тут мне прилетела срочная задача — поправить критический баг в ветке main. Что делать? Создавать коммит с сообщением «WIP» — Work In Progress (в процессе) — практика не очень. И меня выручил git stash (от англ. stash — «прятать», «припрятывать»).
Эта команда позволяет временно «спрятать» все незакоммиченные изменения — и подготовленные, и нет. И возвращает рабочий каталог в состояние последнего коммита.
- В своей ветке с незаконченной работой пишем:
git stash
Всё, папка чиста, как и совесть, как будто мы и не начинали работать. - Можем спокойно переключиться на main, создать ветку для бага, исправить его, сделать коммит и вернуться обратно в свою рабочую ветку feature/header.
- Чтобы вернуть все «спрятанные» изменения, пишем:
git stash pop
Незаконченные правки снова с нами, и можно продолжать с того места, где остановились.
git rebase –interactive
Когда мы работаем над задачей, у нас может накопиться много «рабочих» коммитов: «добавили кнопку», «поправили отступ», «переименовали переменную», «ещё один фикс». Перед тем, как вливать свою ветку в main, хорошо бы прибраться и объединить эти мелкие коммиты в один или несколько. Это поможет сделать историю проекта чистой и понятной.
Для такой уборки используем интерактивный режим git rebase -i. Его можно назвать «git commit --amend на стероидах».
Допустим, у нас в ветке есть 3 лишних коммита. Мы можем сказать Git: «Хотим пересмотреть последние 3 коммита»:
git rebase -i HEAD~3
Git откроет в терминале текстовый редактор со списком этих коммитов. Напротив каждого коммита будет стоять слово pick (выбрать).
Здесь мы можем давать команды:
- pick: оставить коммит как есть;
- reword: оставить коммит, но изменить его сообщение;
- squash или s: объединить этот коммит с предыдущим. Можем написать новое, общее сообщение для них;
- drop или d: просто удалить коммит.
Например, чтобы объединить три коммита в один, мы можем оставить pick у первого, а у второго и третьего заменить его на squash. Git выполнит слияние и предложит написать одно общее сообщение для нового коммита.
rebase
rebase — это инструмент, который переписывает историю. Он создаёт новые коммиты вместо старых.
Всегда, всегда предупреждаем команду, если используем git rebase на публичных ветках (main, master) или любых других ветках, которые уже были отправлены на удалённый сервер и используются другими людьми.
Переписывание общей истории грозит огромными проблемами у коллег при попытке синхронизировать репозиторий. Используем rebase только для наведения порядка в собственнной локальной ветке, до того, как мы отправим её на GitHub и создадим Pull Request.
Pull Request как центр всего
При работе в команде прямой push в основную ветку main делать не стоит. Это главная, «чистовая» ветка, и любой код, который в неё попадает, должны проверить другими участниками команды. Для этого мы используем механизм Pull Request — или Merge Request в GitLab и других системах.
Pull Request (PR) — это, по сути, заявка на слияние собственной ветки с основной. Это не команда Git, а функция веб-интерфейса GitHub.
Типичный рабочий процесс в команде (Git Flow)
Вот как выглядит стандартный цикл работы над задачей от начала до конца:
- Обновление. Прежде чем начать новую задачу, убедись, что твоя локальная main ветка в актуальном состоянии.
git checkout main— переключаемся на основную ветку.git pull origin main— забираем все свежие изменения с GitHub.
- Создание ветки. Создаём новую ветку для своей задачи от актуальной версии main. Название ветки должно отражать суть задачи (например, feature/user-login или fix/header-bug).
git checkout -b feature/user-login
- Работа и коммиты. Пишем код, делаем коммиты. Стараемся, чтобы каждый коммит был логически завершённым и имел понятное сообщение.
Можем делать много мелких коммитов — перед созданием Pull Request их можно будет «причесать» с помощью интерактивного rebase.
- Отправка ветки на GitHub. Когда задача готова (или хотя бы готова к первой проверке), отправляем свою ветку на удалённый сервер.
git push -u origin feature/user-login
- Создание Pull Request. Заходим на сайт GitHub. Он, скорее всего, сам заметит новую ветку и предложит создать Pull Request. Нажимаем на кнопку, получаем результат
- Нам откроется форма создания PR. Пишем нормальный заголовок (чтобы все всё поняли) и добавляем описание: что мы сделали, как это проверить, какие моменты могут быть неочевидны. Чем лучше мы опишем свою работу, тем проще коллегам будет её проверить.
- Код-ревью. Тут начинается самое интересное. Коллеги смотрят на предложенные нами изменения прямо в интерфейсе GitHub. Они могут оставлять комментарии к любой строке кода, задавать вопросы или просить исправить часть. Это и есть код-ревью.
- Доработка. Если коллеги попросили что-то изменить, мы продолжаем работать в своей ветке feature/user-login локально. Делаем новые коммиты, исправляем замечания и отправляем их на GitHub командой git push. Все новые коммиты автоматически добавятся в уже существующий Pull Request.
- Слияние (Merge). Когда все замечания устранены и команда дала нам всё окнула (обычно в GitHub ставят Approve), наш Pull Request готов к слиянию. Чаще всего это делает старший разработчик (или мы сами, если есть права). Он нажимает зелёную кнопку Merge pull request в интерфейсе GitHub.
- Уборка. После слияния наша ветка feature/user-login больше не нужна. Её можно удалить и на GitHub (обычно для этого есть специальная кнопка после мёрджа), и у себя локально (git branch -d feature/user-login).
Бонус: git blame
Когда мы работаем в команду, бывает такое, что кто-то обнаружил чей-то баг. Или просто не может понять логику кода и хочется уточнить её у автора.
Для таких случаев в Git есть команда git blame (от англ. blame — «винить»). Несмотря на название, её главная цель — найти не виновного, а нужного для консультации человека.
Эта команда показывает, кто последний раз изменял файл и в каком коммите это произошло. И всё это для каждой строки кода.
git blame <путь_к_файлу>
После мы увидим содержимое файла, где каждая строка будет снабжена информацией: хеш коммита, имя автора и дата изменения.
И так мы видим, что вот эту функцию 3 месяца назад написал Вася. И теперь мы идём к нему и спрашиваем, зачем он это сделал. Это гораздо продуктивнее, чем пытаться самому полдня расшифровать чужой код или писать в общий чат «Парни, кто это делал?».
Так не боимся названия и с чистой совестью blame всех причастных.
Что дальше: полезные утилиты и материалы для изучения
Вот так мы очень быстренько пробежались по Git. Если вы хотите узнать о нём побольше — и начать ещё лучше его понимать — собрали для вас несколько полезных штук.
Интерактивные песочницы и визуализаторы
- Visualizing Git — наш фаворит — симулятор Git в браузере. Он показывает, что происходит с репозиторием, коммитами и ветками после каждой команды. Можно вводить команды (commit, branch, merge, rebase и т.д.) и в реальном времени видеть, как меняется дерево коммитов. Идеально для всех, кто хочет разобраться в сложных концепциях вроде rebase без страха что-то сломать в реальном проекте.
- Learn Git Branching — ещё один интерактивный тренажёр. Он построен в виде игры с уровнями. Каждый уровень — это небольшая задача, которую нужно решить с помощью команд Git, например, создать определённую структуру веток или перестроить историю коммитов. Тренажёр визуализирует результат и даёт обратную связь.
Стандарты и лучшие практики
- Conventional Commits — это спецификация. Или некое соглашение о том, как стоит писать сообщения к коммитам. Она предлагает простой и структурированный формат (<тип>: <описание>), например, feat: add user login functionality или fix: correct typo in footer. Это помогает сделать историю коммитов читаемой, позволяет автоматически генерировать списки изменений (changelogs) и упрощает навигацию по проекту.
- gitignore.io — крошечная, но невероятно полезная утилита, которая генерирует файл .gitignore. Достаточно просто ввести, какие языки, фреймворки и операционные системы используются в проекте (например, Node, React, macOS). Тогда сервис создаст готовый файл .gitignore со всеми служебными файлами и папками, которые не нужно добавлять в репозиторий.
Книги и документация
- Книга «Pro Git» (на русском языке) — это библия по Git от Скотта Чакона и Бена Страуба. Всё бесплатно и онлай. В ней подробно и с примерами рассматривается всё: от самых азов до внутреннего устройства Git и сложных техник работы.
- Официальная документация Git — если нужно узнать, как работает конкретная команда и какие у неё есть параметры, лучше официальной документации ничего не найти. Она всегда самая актуальная. Каждую команду можно найти на сайте git-scm.com/docs/git-.