Учимся работать с GIT проще некуда

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

Потом появились системы, которые контролировали доступ к файлам. Они просто делали все файлы по умолчанию только для чтения, и чтобы внести изменения программисты должны были помечать целый файл как занятый под себя и изменять его. Во время установки этой пометки файл реально копировался локально программисту и помечался в системе как занятый. Программист мог менять файл и потом забрасывать его обратно на сервер. Этот подход работал неплохо для пары человек, но для большого проекта с большим количеством программистов он превращался в кошмар. У меня на сайте в разделе статей до сих пор есть уроки по работе с VSS от 2009-го года, я храню их на память.

И вот Линус Торвальдс создает систему управления кодом git. Где-то я слышал, что Линус не очень хорошо умеет общаться с людьми и git был создан как раз для того, чтобы сократить коммуникации с людьми до минимума. Не знаю, правда это или нет, но результат все же впечатляющий.

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

Установка

Итак, давайте знакомиться с git. Я все примеры буду выполнять в терминале на macOS, в Windows все работает абсолютно также. Заходим на сайт https://git-scm.com/downloads и здесь есть возможность скачать GIT для Windows, Linux или macOS.

Установка в Windows банальна – для этой ОС существует удобный и красивый мастер установки, в котором можно выбирать все по умолчанию, главное убедитесь, что установлена интеграция с PowerShell. После установки у вас появится выбор – работать в командной строке git bash или PowerShell. Если вы работаете в Windows, то я подозреваю, что второй будет для вас более привычным.

После завершения установки в проводнике можно будет кликнуть правой кнопкой мыши на любой папке и там должен быть пункт меню Git Bash Here, который запустит Bash терминал для работы с git:

В Windows я чаще работаю с PowerShell. Просто запустите его, создайте где-нибудь пустую папку для тестов и в ней выполняйте команды, которые мы будем рассматривать дальше. Обязательно практикуйтесь.

В Linux и macOS установка выполняется из командной строки. В Linux у меня ни разу проблем не было, а вот в macOS была, поэтому рассмотрим установку на маке.

Если у вас еще не установлен Brew, то рекомендую сделать это. Инструкции можно найти здесь https://brew.sh/. Если вы не уверены, установлен он или нет, то запустите терминал и выполните команду:

brew –version

Если нет ошибок и вы увидели версию, то brew установлен.

Теперь выполняем команды

brew update
brew install git

Здесь может произойти ошибка, если нет прав на запись в папку /usr/local/sbin. Запускать их под админа смысла особо нет, вместо этого прямо в ошибке вам должны предложить выполнить следующую команду, чтобы дать своему пользователю права на папку /usr/local/sbin.

chown -R $(whoami) /usr/local/sbin

Если ошибки не было при установке git, то у вас права наверно уже были исправлены и не нужно выполнять chown.

И напоследок установим git-gui – графические утилиты для работы с git. Он не обязателен, если вы будете работать из командной строки, но я его все же ставлю, когда нужно посмотреть на историю изменений. В Windows gui утилиты ставятся автоматически, а в macOS нужно отдельно выполнить команду:

brew install git-gui

На мой взгляд стандартные графически утилиты git ужасные с точки зрения дизайна и интерфейса, но для меня это не проблема, потому что я ими реально пользуюсь очень редко. Я буду показывать, как работать с git из командной строки, потому что я считаю это очень важным навыком. Когда вы научитесь, то можно в дополнение установить утилиты с графическим интерфейсом, с более приятным внешним видом, чем стандартные. Такие утилиты можно найти здесь https://git-scm.com/downloads/guis.

Первое, что можно сделать после установки, это указать свое имя и e-mail. Это необходимо, чтобы git мог использовать эту информацию при создании коммита. Выполните две следующие команды:

git config --global user.name mflenov
git config --global user.email mikhail@flenov

только замените mflenov на свое имя и mikhail@flenov свой email. Кстати, этот email не существует, так что не пишите мне на него, я не смогу ответить. Даже если вы добавите .info или .ru, такого email все равно не будет.

Последовательность выполнения команд не важна. После выполнения первой из них, git создаст файл.gitconfig в вашей домашней директории и сохранит в нем введенную вами информацию.

Если вы работаете в macOS или Linux, то попробуйте сейчас выполнить команду:

cat $HOME/.gitconfig

В результате вы должны увидеть:

[user]
    email = mikhail@flenov.ru
    name = mflenov

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

Инициализация

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

git init

В результате вы должны увидеть что-то типа:

Initialized empty Git repository in /Users/mikhailflenov/Projects/youtube-demo/.git/

Здесь говориться, что создан новый репозиторий GIT и нам показана папка .git. Имена папок, которые начинаются с точки по умолчанию не видны в Linux и macOS и это хорошо. В этой папке git хранит свои внутренние вещи, в которые вас очень редко нужно будет заглядывать.

Командой git init вы создали репозиторий и ствол дерева вашего проекта, который будет называться master, а по последним рекомендациям его стали называть main. Я буду продолжать использовать старое название master.

Инициализация выполняется в принципе один раз на проект, когда вы создаете что-то новое. После этого забываем про git init.

Первая команда, которую вы скорей всего будете выполнять чаще всего git status. Выполните эту команду

git status

и в результате вы должны увидеть на экране:

On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)

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

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

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

echo hallo >> readme.txt

Теперь нужно добавить этот файл к git, чтобы он знал о нем, для этого выполняем команду

git add readme.txt

git отслеживает изменения файлов, которые вы добавляете в него и позволяет сохранить (закомитить) изменения и каждый коммит сохраняется в истории git.

Первый файл добавлен, теперь нужно сделать первое сохранение:

git commit -m 'initial commit'

Здесь мы с помощью команды git commit говорим, что нужно закоммитить, или зафиксировать добавленные файлы. Ключ -m позволяет добавить сообщение/комментарий (-m). Initial commit это и есть мой комментарий к первому коммиту.

Обратите внимание на результат команды:

 [master (root-commit) 3167f60] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 readme.txt

В первой строке нам говорят, что мы создали корневой коммит (root-commit) под номером 3167f60. Номера уникальны и генерируются с помощью алгоритма sha. Таким образом git создает точки сохранения. На диаграмме веток, которую я недавно показывал, это точки #1, #2 и #3.

Во второй строке дается статистика коммита и нам говорят, что изменен один файл и в нем изменена только одна строка.

Выполните сейчас команду gitk, чтобы посмотреть на визуальное представление

Слева наверху будет дерево, пока мы видим только корневой коммит. Сверху в центре – имя пользователя, который сделал изменения. Сверху справа – время изменения.

Обратите внимание на строку, которую я подчеркнул в середине красным цветом. Это Sha1 код, который был назначен коммиту. Мы уже видели его раньше, но только первые 7 символов 3167f60. Здесь же мы можем увидеть полный код. Очень редко бывает необходимость знать полный код, обычно достаточно короткого кода, который вы видели при создании коммита.

Работа с ветками кода

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

У меня master установлен на сервере staging от которого мы запускаем код на рабочие сервера. Клиент на этом сервере может делать изменения в параметрах, которые хранятся в конфигурационных файлах, и программисты могут пофиксить на этом сервере мега срочные баги, но только в очень редких случаях.

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

Прежде чем что-то делать, нужно создать новую ветку, куда мы будем добавлять наш код. Что такое ветка кода? Реально представьте себе дерево. У вас есть ствол, и на верхушке ствола мы создаем ответвление, в котором работаем, пишем свой код, а когда работа закончена, то объединяем содержимое ветки со стволом.

Синяя ветка – это основное дерево. Когда мы создали красную ветку, то в ней фиксируется состояние кода на момент создания ветки, то есть то, что было в левой точке пересечения синей и красной линии. Теперь мы в своей ветке можем работать над кодом и сохранять его. На рисунке я # с цифрой я показал возможные точки сохранения и их оказалось три. Когда работа закончена, мы сливаем ветку с основным деревом в точке пересечения со стрелкой справа. В этот момент изменения кода #1, #2 и #3 попадают в основную ветку и становятся доступными в master.

Даже если в голове до сих пор не сформировалась окончательная картина, надеюсь в процессе этого вы все же увидите, как работает ветвление.

Итак, первое, с чего мы должны начать – создание ветки. Для этого выполняем команду:

git checkout -b имяветки база

git checkout говорит, что мы должны переключиться на репозиторий. Ключик -b говорит, что нужно не просто переключиться, а создать новую ветку с именем имяветки. Именование веток у каждого свое. Когда я работал в консалтинге над разными проектами, то именование состояло из двух частей:

имясайта/номертикета

или если я работал над чем-то большим, то имя имело формат:

имясайте/имяпроекта

Например, когда мне нужно было исправить баг под номером 415412 для сайта wheeloffortune, то я создавал ветку с именем:

wof/415412

По левой части сразу видно, что этот фикс нужно искать в репозитории для сайта wheeloffortune и описание фикса можно найти в тикете 415412.

Если нужно было работать над новым функционалом и это целый проект по редизайну на пару месяцев для сайта sonyrewards, то я мог назвать ветку:

sr/redesign2015

Сейчас у нас в компании ветки называют по имени команды + номер тикета:

teamname/415412

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

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

git checkout -b имяветки origin/master

Стоп, еще немного о именовании. В данном случае я указываю origin/master и это удаленный ствол. На это указывает слово origin. Если мы создаем новую ветку fixdone/345321, то это локальная копия на нашем диске. Удаленная копия на сервере git в репозитории будет иметь имя origin/fixdone/345321. Когда мы создаем новые ветки, то желательно создавать от удаленной версии master, но у нас ее пока нет, поэтому если попытаться выполнить такую команду, то она завершиться ошибкой.

Да, я рекомендую всегда использовать в качестве базы удаленную версию origin/master, которая указывает на версию на сервере, но если ее нет, то придется использовать локальную – просто master. Мы пока создали только локальный репозиторий. Пока нет удаленного, придется использовать локальный. Как только появиться удаленный, всегда используйте его. О удаленных ветках мы поговорим в следующий раз.

Итак, пока нет удаленного мастера, давайте создадим новую ветку от локального:

git checkout -b initialwork master

Я назвал ветку initialwork. В результате выполнения команды вы должны увидеть что-то типа:

Switched to a new branch 'initialwork'

Теперь мы находимся в ветке, где мы можем исправлять баг или работать над новым функционалом. Давайте создадим файл index.html. Вы можете воспользоваться для этого любым текстовым редактором.

Я создал index.html с таким содержимым:

<html>
    <head>
        <title>Welcome</title>
    </head>
    <body>
        <h1>Home page</h1>
        <p>Welcome to my website</p>
    </body>
</html>

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

Выполняем команду git status, чтобы посмотреть текущее состояние:

On branch initialwork
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	index.html

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

В первой строке нам напоминают, что мы находимся на ветке initialwork. Потом сообщают, что у нас в папке есть файл index.html, который не добавлен в git и изменения в файле не отслеживаются. Тут же есть подсказка, что для добавления файла в git нужно выполнить комануд git add <file>. Мы уже это делали разок, давайте добавим index.html:

git add index.html

Снова выполняем git status, чтобы посмотреть, что изменилось:

On branch initialwork
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
	new file:   index.html

Мы все еще находимся на той же ветке и мы добавили файл, который будет сохранен в git, но он еще не закомичен. Чтобы окончательно закомитить изменения, нужно выполнить команду git commit. Если вы передумали, и не хотите коммитить изменения в файле index.html, то отменить можно командой:

git restore --staged index.html

На то, как можно отменить добавление указывает подсказка при выполнении git status:

  (use "git restore --staged <file>..." to unstage)

Эта команда уже менялась, да если честно я ее я никогда не пытался запомнить ее, потому что подсказку можно всегда увидеть в git status.

Когда вы выполняете команду git add, вы подготавливаете свой коммит, по другому эту операцию на английском называют stage. Когда вы убираете файл, эта операция называется unstage. В некоторых программах вместо add и restore вы можете увидеть именно эти слова stage и unstage.

Но давайте не будем отменять, а закомитим файл. Если вы уже выполнили restore, то снова добавьте файл и давайте закомитим командой:

git commit -m 'add index.html file'

На этот раз я коммичу файл с сообщением 'add index.html file'. В консоли вы должны увидеть что-то типа:

[initialwork 2255b8f] add index.html file
 1 file changed, 9 insertions(+)
 create mode 100644 index.html

Выполните команду gitk, чтобы посмотреть, какие произошли изменения. Слева вверху теперь уже две коммита. Пока они не выглядят как дерево, потому что мы просто создали последовательно две точки. Но напротив каждой из точек виден комментарий, который мы добавили при коммите, поэтому по этому комментарию можн легко найти нужно изменение в дереве:

Попробуйте сейчас изменить файл index.html и выполните команду git status. Результат должен быть примерно следующим:

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:   index.html

Обратите внимание, что в последней строки перед именем файла index.html появилась надпись modified. Чтобы сохранить изменения нужно снова добавить файл в коммит и закоммитить. Для добавления в коммит можно использовать команду git add. Если изменено много файлов, то их можно добавлять по маске

git add i*

Так мы добавим все файлы, имена которых начинаются с i.

Если вы хотите добавить в коммит все измененные файлы, то можно использовать ключ -u, что означает updated:

git add -u

Эта команда добавит только те файлы, котоыре изменены и за которыми уже наблюдает git. Новые файлы не будут добавлены, их можно потом добавить отдельно выполнив add.

Сливаем ветки

В файловом менеджере или в терминале с помощью команды ls посмотрите на файлы, которые у нас есть. Их должно быть два readme.txt и index.html.

Попробуем переключиться на другую ветку. Создайте новую ветку от мастера с именем secondone:

git checkout -b secondone master

Мы создали новую ветку от мастера. Давайте посмотрим на файловую систему. Обратите внимание, что файл index.html исчез. Когда мы создали новую ветку и переключились на нее, то мы видим только то, что в данный момент находиться в мастере. Index.html файла там нет, он живет в отдельной ветке initialwork.

Если нам нужны изменения, которые были сделаны в файле initialwork, то мы можем слить их. Для этого можно выполнить команду git merge и указать имя ветки, которую нужно слить:

git merge initialwork

В результате вы должны увидеть примерно следующее:

Updating 3167f60..2255b8f
Fast-forward
 index.html | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 index.html

Теперь в файловой системе можно увидеть файл index.html.

Наши изменения начали ветвиться, как показано на следующем рисунке. Теперь понятно, почему

Но изменения все еще не в мастере. Мы можем переключиться на мастер:

git checkout master

и посмотреть на файловую систему. У нас тут все еще только readme.txt.

Обратите внимание, что при переключении на мастер я выполнял команду git checkout без ключа -b, потому что ветка master уже существует и нам не нужно ничего создавать, поэтому просто git checkout – переключиться без создания.

Теперь мы можем слить с мастером любую ветку initialwork или secondone. В обоих ветках уже есть файл index.html и в любом случае он появиться в мастере. Так что можно выполнить команду:

git merge initialwork

или

git merge secondone

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

git merge initialwork
Updating 3167f60..2255b8f
Fast-forward
 index.html | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 index.html

git merge secondone
Already up to date.

Огромный плюс в том, что для изменения файлов мы никогда и ничего не блокировали, никому не сообщали, что сейчас мы начнем работать над файлом и пожалуйста не трогайте их. Мы просто меняем файлы, сохраняем изменение и потом сливаем нужные ветки вместе. В git сохраняются только изменения, а не весь измененный файл. Это значит, что при слиянии двух веток, в которых изменен один и тот же файл, но в разных местах файла проблем не будет. Только если два программиста изменили одну и ту же строку в файле возникнут проблемы, но об этом стоит поговорить в следующий раз.



Внимание!!! Если ты копируешь эту статью себе на сайт, то оставляй ссылку непосредственно на эту страницу. Спасибо за понимание

Комментарии

СергейП

10 Июня 2022

Прочитал с удовольствием, спасибо!


Иван

02 Ноября 2022

Здравствуйте. А можете подсказать, или быть может направить. Имеется файл базы данных fdb. Как с ним работать через GIT нескольким людям. Это ведь не текстовый файл. Как будет выглядеть работа с файлом, если два человека одну и ту же таблицу правят?
Спасибо за ответ.


Михаил Фленов

02 Ноября 2022

GIT создан для работы с кодом, а не базами данных. Через GIT с бинарными файлами совместно работать нельзя. Бинарными можно хранить, но сливать их git не будет.


Добавить Комментарий

О блоге

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

Обратная связь

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

Пишите мне