Практическое руководство по использованию Git. Часть 2

0
518
views

Перевод второй части статьи «How to Use Git and Git Workflows – a Practical Guide».

В первой части статьи мы рассмотрели установку Git и настройку аккаунта на GitHub, создание нового репозитория на GitHub, клонирование репозитория, ветвление. Также мы научились просматривать текущее состояние проекта и сделали свой первый коммит.

В этой части мы рассмотрим:

Как запушить коммит на GitHub

У нас есть новый коммит на нашей локальной машине. Теперь нам нужно обновить наш «источник истины» — удаленный origin-репозиторий (GitHub).

В настоящее время локально мы находимся в ветке main. Нам нужно сообщить GitHub-у, чтобы он обновил собственную ветку main этим новым коммитом.

Для этого используется команда git push (push — «толкать, пихать»). Мы можем указать, куда именно мы хотим запушить коммит и в какую конкретно ветку.

(main)$ git push origin main
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 326 bytes | 326.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:johnmosesman/practical-git-tutorial.git
   2592324..a8f8b95  main -> main

Здесь мы запушили изменения в origin (GitHub), в ветку main.

Вывод команды сообщает нам об операциях с файлами, которые пришлось совершить Git, а последняя строка говорит о том, какие коммиты были запушены и куда:

To github.com:johnmosesman/practical-git-tutorial.git
   2592324..a8f8b95  main -> main

Мы видим, что мы запушили нашу ветку main в ветку main на GitHub.

Если мы посмотрим лог проекта (git log), мы заметим, что теперь ветки main и в локальном репозитории, и в origin нацелены на один и тот же коммит.

(main)$ git log
commit f5b6e2f18f742e2b851e38f52a969dd921f72d2f (HEAD -> main, origin/main, origin/HEAD)
Author: John Mosesman <johnmosesman@gmail.com>
Date:   Mon Mar 22 10:07:35 2021 -0500

    Added the intro line to chapter 1

В общем, в origin (GitHub) в ветке main (origin/main) последним коммитом в истории теперь выступает наш коммит.

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

Добавляем еще один коммит в Git

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

Добавим в наш текстовый файл еще одну строку:

(main)$ echo "It was the best of times, it was the worst of times" >> chapter-1.txt
(main)$ cat chapter-1.txt
Chapter 1 - The Beginning
It was the best of times, it was the worst of times

Команда cat позволяет нам просмотреть файл. Мы видим, что теперь в нем две строки.

Давайте еще раз проверим статус нашего Git-репозитория:

(main)$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   chapter-1.txt

no changes added to commit (use "git add" and/or "git commit -a")

В самом верху написано, что наша ветка полностью соответствует origin/main.

Это может показаться странным, ведь мы только что изменили файл. Но здесь Git сравнивает только коммиты, которые мы совершили, с коммитами в origin/main (а не изменения вообще).

В следующем разделе дается немного больше информации:

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   chapter-1.txt

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

Как вносить изменения в стейджинг

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

(main)$ git add .
(main)$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   chapter-1.txt

Теперь эти изменения готовы к коммиту. Но прежде чем сделать коммит, давайте изменим кое-что в файле chapter-1.txt.

Я полностью заменю содержимое этого файла новым текстом.

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

(main)$ echo "New file contents" > chapter-1.txt

(main)$ cat chapter-1.txt
New file contents

(main)$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   chapter-1.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   chapter-1.txt

В выводе git status мы видим, что у нас есть и подготовленные, и неподготовленные изменения («Changes to be committed» и «Changes not staged for commit»).

Хотя в самом файле содержится один вариант текста, Git отслеживает для нас оба изменения. Даже несмотря на то, что это изменения одних и тех же строк!

Но приведенный выше вывод команды не дает нам информации о том, что это были за изменения. Мы знаем лишь об их существовании.

Чтобы просмотреть эти изменения, давайте сначала воспользуемся командной строкой (сам я никогда не применяю ее с этой целью), а затем используем GUI (что куда удобнее).

Как просматривать разницу между изменениями в Git

Чтобы увидеть изменения, нам нужно просмотреть в Git diff.

diff (сокр. от difference, «разница») — это разница между двумя наборами изменений. Это может быть разница между подготовленными и неподготовленными изменениями или же разница между коммитами.

Чтобы посмотреть diff в командной строке, используется команда git diff.

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

(main)$ git diff
diff --git a/chapter-1.txt b/chapter-1.txt
index 0450d87..4cbeaee 100644
--- a/chapter-1.txt
+++ b/chapter-1.txt
@@ -1,2 +1 @@
-Chapter 1 - The Beginning
-It was the best of times, it was the worst of times
+New file contents

Мой терминал пытается расцвечивать результат для улучшения читаемости. В выводе команды мы видим название файла, который изменился (chapter-1.txt), а под ним — собственно изменения. Давайте обратим внимание на следующие строки:

-Chapter 1 - The Beginning
-It was the best of times, it was the worst of times
+New file contents

Строки, начинающиеся со знака минус (-), — это строки, которые мы полностью удалили. Строки, начинающиеся со знака плюс (+) — те, которые мы добавили.

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

Программа, которой пользуюсь я, называется GitX. Она давно вышла в тираж и уже даже не поддерживается. Но для просмотра diff-ов годится.

Я не то чтобы рекомендовал вам именно эту программу, но она бесплатная, так что можете попробовать. Еще есть десктопный клиент для GitHub. Сам я никогда им не пользовался, но это, вероятно, хороший вариант.

Итак, после этого маленького отступления, давайте посмотрим, как выглядит diff в моем инструменте.

Для начала, с правой стороны, в подготовленных изменениях мы видим наше вставленное второе предложение:

Подготовленные изменения в GitX

В неподготовленных изменениях с левой стороны мы видим полное удаление двух строк и добавление новой строки:

Неподготовленные изменения в GitX

Это соответствует тем командам, которые мы выполняли.

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

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

Итак, мы рассмотрели, как работает стейджинг и Git diff. Теперь давайте сбросим наши неподготовленные изменения, чтобы вернуться и закоммитить наше первое изменение.

Последний вывод git status, собственно, подсказывал нам, что мы можем это сделать при помощи команды git restore. Мы можем передать этой команде путь к файлу или поставить точку, чтобы «захватить» всю директорию.

(main)$ git restore .

Если мы проверим статус еще раз, мы увидим, что вернулись к нашим подготовленным изменениям и готовы к коммиту.

Примечание. Git позволяет коммитить только те изменения, которые находятся в стейджинге (т. е. подготовленные). Поэтому мы могли бы оставить неподготовленные изменения в нашей рабочей директории и это никак не помешало бы процедуре коммита.

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

Давайте, наконец, закоммитим эти изменения, добавив сообщение о том, что именно мы сделали:

(main)$ git commit -m "Added the intro line to chapter 1"
[main f5b6e2f] Added the intro line to chapter 1
 1 file changed, 1 insertion(+)

Проверяем статус проекта еще раз и видим, что наша ветка на 1 коммит опережает origin/main:

(main)$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

Давайте теперь запушим изменения:

(main)$ git push origin main

Совместная работа в Git

Пока мы рассматривали простейший случай: работу одного человека в одной ветке.

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

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

В целом, хорошим тоном считается НЕ работать напрямую в ветке main.

Главная ветка призвана быть «источником истины» для проекта, и изменения, вносимые в нее, должны тщательно проверяться. Любое изменение в origin/main становится источником истины для любого человека, работающего над этим проектом, поэтому все изменения вносятся обдуманно и после код-ревью.

Вместо того чтобы работать непосредственно в main , давайте сделаем ответвление и создадим собственную ветку для того функционала, над которым работаем (feature branch). Все внесенные изменения мы потом сольем (смержим, merge) обратно в main.

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

Ветки отдельных функций в Git

Для начала давайте сделаем ответвление main и создадим отдельную ветку для нашей функции.

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

Чтобы это проверить, давайте создадим новую ветку chapter-2. Для этого мы используем команду git checkout с флагом -b и указываем имя новой ветки:

(main)$ git checkout -b chapter-2
Switched to a new branch 'chapter-2'
(chapter-2)$

Обратите внимание, что в строке предложения терминал теперь показывает название новой ветки, chapter-2. Изменения, которые мы внесем в chapter-2, никак не заденут main. У нас по сути появилась новая песочница, где мы можем менять что угодно, не рискуя навредить main.

«Под капотом» здесь происходят любопытные вещи, но для целей этого руководства нам нужно лишь знать, что в Git «checkout» означает «сделай так, чтобы мой локальный проект выглядел в точности так же, как весь проект выглядел в определенный момент». Можете считать, что ветка — указатель, указывающий на определенный момент в Git-истории.

При этом происходит много всего другого, но пока вам хватит и этого определения.

Итак, у нас есть новая ветка и пока что она идентична main (мы же еще не вносили никаких изменений).

Теперь давайте повторим то, что мы уже делали прежде. Создадим новый файл chapter-2.txt, поместим в него кое-какой контент и закоммитим:

(chapter-2)$ touch chapter-2.txt
(chapter-2)$ echo "Chapter 2 - The next chapter" >> chapter-2.txt

(chapter-2)$ git status
On branch chapter-2
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        chapter-2.txt

nothing added to commit but untracked files present (use "git add" to track)

(chapter-2)$ git add .

(chapter-2)$ git commit -m "Creates chapter 2 and adds the topic sentence"
[chapter-2 741822a] Creates chapter 2 and adds the topic sentence
 1 file changed, 1 insertion(+)
 create mode 100644 chapter-2.txt

Тут ничего нового, все то же, что и с Главой 1.

Теперь у нас в ветке chapter-2 есть новый коммит. Давайте посмотрим, как выглядит лог проекта.

(chapter-2)$ git log
commit 741822a9fd7b15b6e3caf437dd0617fabf918449 (HEAD -> chapter-2)
Author: John Mosesman <johnmosesman@gmail.com>
Date:   Mon Mar 22 10:33:26 2021 -0500

    Creates chapter 2 and adds the topic sentence

commit f5b6e2f18f742e2b851e38f52a969dd921f72d2f (origin/main, origin/HEAD, main)
Author: John Mosesman <johnmosesman@gmail.com>
Date:   Mon Mar 22 10:07:35 2021 -0500

    Added the intro line to chapter 1

commit a8f8b95f19105fe10ed144fead9cab84520181e3
Author: John Mosesman <johnmosesman@gmail.com>
Date:   Fri Mar 19 12:27:35 2021 -0500

    New chapter 1 file with chapter heading
...

В логе мы видим, что последний коммит показывается сверху, а HEAD опять отличается от origin. И это естественно, ведь наших локальных изменений еще нет на GitHub.

Теперь нам нужно вставить наши новые изменения в ветку main. Этим мы займемся в следующей части.

ОСТАВЬТЕ ОТВЕТ

Please enter your comment!
Please enter your name here