- Для Windows скачать и запустить Standalone Installer
- Для Linux
- Для MacOS
- На официальном сайте Homebrew скопировать команду и выполнить в консоли
- Выполнить в консоли команду
brew install git
Чтобы удостовериться, что git установлен в систему, должна вылететь инфа о версии программы. Если не вылетело, значит git не установлен.
$ git --version
Чтобы коммиты были от чьего-то имени, надо заполнить некоторые настройки. В консоли выполнить:
$ git config --global user.name "User Namovich"
# имя или ник нужно написать латиницей и в кавычках
$ git config --global user.email [email protected]
# здесь нужно указать свой настоящий email
Все глобальные настройки Git хранит в файле .gitconfig
в домашней директории. Команда запишет в этот файл указанные имя и почту. Чтобы убедиться в этом, можно вызвать команду для чтения файлов.
$ cat ~/.gitconfig
Другой способ проверки — вывести содержимое файла конфигурации Git той же командой git config
с флагом --list
(англ. «список»).
$ git config --list
$ cd ~ # перейти в домашнюю директорию
$ pwd # запомни, это домашняя директория
Например, есть такое дерево директорий (папок):
/home
/username
/projects
/github
/open source project
/practicum
/my-project
/desktop
/documents
doc.txt
/photos
$ pwd # вывести директорию, в которой сейчас находишься
$ /home # вывелось, что мы в home
$ cd username/projects/practicum # перешли в practicum
$ cd .. # переметситься в родительскую директорию (на директорию выше текущей)
# в нашем примере из practicum попадем в projects
$ cd ../.. # переместиться уже из projects на две директории выше, то есть в home
$ cd u[Tab] # сработает автодополнение до возможного варианта, если вариант один
# иначе надо нажать еще раз [Tab] -- выведутся все варианты перехода,
# начинающиеся с 'u'
$ pwd
$ /home/username/
$ cd [Tab][Tab] # показать варианты директорий,
# куда можно переместиться из текущей директории
# выведется projects, desktop и documents, в них и можно перейти
$ cd projects/practicum # перешли в practicum
$ cd my-project # перешли в my-project
Чтобы перейти в username
, надо либо указать абсолютный путь (это путь от корня, корень это '/'), либо переходить двумя точками и слешами
$ cd /home/username # вариант 1, кстати все 'cd путь' -- путь назывался относительным
$ cd ../../.. # вариант 2
Tip
Символами cd /
и cd ~
можно быстро перемещаться к корневой и домашней директориям.
$ ls # вывести список файлов и директорий в текущей директории
$ ls -la # вывести список в том числе скрытых файлов и директорий в текущей
# директории
$ clear # очистить окно консоли
$ touch my-new-file.txt # создали файл my-new-file.txt в текущей директории
$ mkdir new-dir # создали директорию new-dir
Можно создать целую структуру директорий одной командой с помощью флага -p
.
$ mkdir -p dir1/dir-inside/dir-deeper-inside
# создали папку dir-deeper-inside в папке dir-inside, которая находится в папке dir1
# комадны можно объединять через &&
$ mkdir first-project && cd first-project # создать директорию first-project и
# перейти в нее
$ mkdir ~/my-git-projects # создаст папку my-git-projects внутри домашней директории
$ touch ../../file.txt # создаст файл file.txt на две папки выше по иерархии
$ cp что_копируем куда_копируем
$ cp index.html src/
# скопировали index.html в папку src
$ cp что_копируем что_копируем что_копируем куда_копируем
$ cp index.html style.css script.js src/
# скопировали три файла (index.html, style.css и script.js) в папку src
[!faq] Подробнее про
cp
$ mv ../file.txt me.png important-files
# Переместить файлы file.txt из родительской директории и me.png
# из текущей директории в папку important-files в рабочей директории
$ rm example.txt # удалили файл example.txt из текущей папки
$ rmdir images # команда удалит папку images из текущей директории,
# если папка images пуста
$ rm -r images # удалили папку images со всем её содержимым из текущей директории
[!ATTENTION] 💡 Будьте осторожны: удаление объектов командами
rm
иrmdir
необратимо — в этом случае файлы и папки не попадают в корзину и исчезают навсегда.
Tip
Примечание: для удаления файла используют rm
, для удаления пустой директории — rmdir
, а для директории с файлами — rm -r
.
Вывод содержимого:
$ cat myfile.txt # распечатали содержимое файла myfile.txt
Редактирование файла:
$ nano myfile.txt # открыли в редакторе nano содержимое файла myfile.txt
# внизу будут символы, позволяющие многое сделать с файлом,
# главное понимать, что ^X это Ctrl + X :)
Запись в файл:
$ echo "Привет!" # выведет "Привет!" как эхо
Привет! # вывело
$ touch file.txt
$ echo "Первая строка файла" >> file.txt # перенаправления вывода не в консоль
# а в конец файла
$ echo "Вторая строка файла" >> file.txt
$ cat file.txt
Первая строка файла
Вторая строка файла
$ echo "Третья строка файла" > file.txt # ОДИН! знак "больше"
$ cat file.txt
Третья строка файла # другие строки пропали, т.к. '>'
# не дописывает в конец файла,
# а перезаписывает файл
Tip
Стрелками вверх и вниз можно вызывать ранее набранные команды.
[!attention] Все команды, начинающиеся с
git...
надо выполнять в локальном репозитории. То есть надо сначала перейти в директорию с репозиторием, и только потом давать команды git.
$ git init # сделать директорию локальным git-репозиторием, который потом можно
# синхронизировать с удаленным репозиторием на github
$ ls -la
total 8
drwxr-xr-x 1 username 197121 0 авг 27 time ./
drwxr-xr-x 1 username 197121 0 авг 27 time ../
drwxr-xr-x 1 username 197121 0 авг 27 time .git/ # В подпапке `.git` Git будет
# хранить всю служебную информацию
[!faq] Директория, в которой лежит
.git
называется локальным репозиторием.
[!ATTENTION] Помните, что не рекомендуется создавать репозиторий Git внутри другого Git-репозитория. Это может вызывать проблемы с отслеживанием изменений.
#IDEA (идея: написать программу, которая проверяет, что текущая директория не является дочерней директорией другого репозитория)
В некоторых случаях при инициализации репозитория Git может показать объёмное сообщение, которое начинается со слов Using 'master' as the name…
. Это не ошибка, подробнее тут -- Black Lives Matter.
$ cd <папка с репозиторием> # перешли в папку
$ rm -rf .git # удалили подпапку .git чтобы "разгитить" ее
[!ATTENTION] Будьте осторожны: в подпапке
.git
хранится история изменений. Если удалить.git
, то вся история проекта будет стёрта без возможности восстановления — останется только последняя версия файлов.
$ git status # показывает текущее состояние репозитория
# (что нового, старого, измененного в нем есть)
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
Команда git status
выведет:
- название текущей ветки:
On branch master
илиOn branch main
; - сообщение о том, что в репозитории ещё нет коммитов:
No commits yet
; - сообщение, которое говорит: «чтобы что-нибудь закоммитить (то есть зафиксировать), нужно сначала это создать» —
nothing to commit (create/copy files and use "git add" to track)
.
[!faq] Коммит — фиксация состояния файлов в Git.
[!faq] Команда
git status
выводит текущее состояние проекта: есть ли незакоммиченные (изменённые) файлы и название текущей ветки.
Tip
В отличие от git init
, команду git status
используют часто. В любой непонятной ситуации стоит посмотреть состояние (статус) репозитория, а потом решить, что делать дальше.
Когда в локальном репозитории появились файлы, их надо начать отслеживать. Помогает в этом команда git add
тремя способами.
$ git add --all # добавили
$ git status # проверили, что добавилось
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: <какой-то файл 1> # зеленый шрифт
new file: <какой-то файл 2> # зеленый шрифт
<...>
$ git add <какой-то файл 1>
$ git add <какой-то файл 2>
Также можно добавить текущую папку целиком — в этом случае все файлы в ней тоже будут добавлены. Обратиться к текущей папке в Bash позволяет точка (.
).
$ git add . # добавить всю текущую папку
$ git status
Если сейчас отредактировать любой из «зелёных» файлов в папке first-project
, он перейдёт в состояние modified
(англ. «изменённый») и будет и в «зелёном», и в «красном» списках.
Отредактируем и снова вызовем git status
в консоли:
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: <какой-то файл 1>
new file: <какой-то файл 2>
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: <какой-то измененный файл 1>
Ключ -m
позволяем задать сообщение для коммита, в котором будут пояснения к этому самому коммиту.
$ git commit -m ‘Мой первый коммит!’
[!faq] 💡 Чем отличается запоминание от сохранения?
Команда
git add
не сохраняет содержимое файлов в репозитории. Само сохранение, или фиксацию состояния файлов, называют коммитом (от англ. commit — «совершать», «фиксировать»). «Сделать коммит» значит сохранить текущую версию файла.Если провести аналогию, команду
git add
можно сравнить с расстановкой людей в кадр, а коммит — сама сделанная фотография.
Команда git commit
выведет информацию о коммите.
[master (root-commit) baa3b6e]
значит:- коммит был в ветке
master
; root-commit
— это самый первый, или «корневой» (англ. root), коммит в ветке, у следующих коммитов такой надписи не будет;baa3b6e
— сокращённый идентификатор коммита (подробнее об этом мы ещё расскажем).
- коммит был в ветке
2 files changed, 1 insertion(+)
значит:- изменились два файла (
readme.txt
иtodo.txt
); - одна строка была добавлена (
1. Пройти пару уроков по Git.
).
- изменились два файла (
- Строки вида
create mode 100644 readme.txt
— это более подробная информация о новых (добавленных в Git) файлах.create
(англ. «создать») говорит, что файл был создан. Если бы файл был удалён, на этом месте было бы словоdelete
(англ. «удалить»).mode 100644
сообщает, что это обычный файл. Также возможны варианты100755
для исполняемых файлов (например,что-нибудь.exe
) и120000
для файлов-ссылок в Linux. Файлы-ссылки не содержат данных сами по себе, а только ссылаются на другие файлы — как «ярлыки» в Windows.
Note
💡 Обратите внимание: после того как вы сделали первый коммит, команда git status
перестала выводить сообщение No commits yet
(англ. «ещё нет коммитов»).
$ git log
commit 0cc2241f3b2314760ffab951cbe10efefed154ee (HEAD -> master)
Author: user_name user_email # инфа из git config
Date: <дата в определенном формате>
Мой первый коммит! # сообщение к коммиту
[!faq] Удаленный репозиторий это не тот, который удалили. Это тот, который на GitHub.
Надо иметь аккаунт на github, чтобы работать дальше. После регистрации заходим с главного экрана Repositories -> New -> задаем имя репозиторию и делаем его приватным или публичным -> Create repository.
[!faq] Чтобы получить доступ к репозиторию на GitHub, вам тоже нужно предоставить ключ, который подтверждает вашу личность и права на чтение или изменение данных.
Когда компьютеры обмениваются данными в сети, они следуют сетевым протоколам (англ. network protocols) — правилам обмена данными между компьютерами. Один из наиболее распространённых сетевых протоколов — SSH (от англ. Secure Shell Protocol). Он обеспечивает безопасный обмен данными в сети.
SSH использует пару ключей для обеспечения безопасности — публичный и приватный:
- Приватный ключ (англ. private key) хранится только на вашем компьютере и не должен передаваться кому-либо ещё. Он используется для расшифровки данных.
- Публичный ключ (англ. public key) доступен всем и используется для шифрования данных. Они могут быть расшифрованы парным приватным ключом.
Только вы можете расшифровать данные с помощью приватного ключа, но любой владелец публичного ключа может их для вас зашифровать. Эти два ключа связаны и образуют SSH-пару.
Прежде чем генерировать SSH-ключи, убедитесь, что у вас их ещё нет. По умолчанию директория с SSH-ключами находится в домашней директории пользователя. Обычно SSH-ключи находятся в директории .ssh/
. Проверить наличие этой директории и файлов в ней можно с помощью следующей команды.
$ cd ~
$ ls -la .ssh/
total 36
drwxr-xr-x 1 grine 197121 0 апр 11 14:03 ./
drwxr-xr-x 1 grine 197121 0 авг 28 17:03 ../
-rw-r--r-- 1 grine 197121 3434 июл 7 2022 id_rsa
-rw-r--r-- 1 grine 197121 747 июл 7 2022 id_rsa.pub
-rw-r--r-- 1 grine 197121 828 апр 11 14:03 known_hosts
-rw-r--r-- 1 grine 197121 656 авг 8 2022 known_hosts.old
Если папка пустая или её нет, всё в порядке. Иначе можно удалить ее, если ключи в ней не нужны. Если не удаляли, то при генерации надо будет прописать путь до нее.
Итак:
- Для генерации SSH-пары можно использовать программу
ssh-keygen
. Откройте терминал и введите следующую команду.
$ ssh-keygen -t ed25519 -C "электронная почта, к которой привязан ваш аккаунт на GitHub"
Используйте электронную почту, к которой привязан ваш GitHub-аккаунт.
Если вы видите сообщение об ошибке, то, скорее всего, ваша система не поддерживает алгоритм шифрования ed25519
. Ничего страшного: используйте другой алгоритм.
$ ssh-keygen -t rsa -b 4096 -C "электронная почта, к которой привязан ваш аккаунт на GitHub"
После ввода отобразится такое сообщение.
> Generating public/private rsa key pair. # сгенерированы публичный и приватный ключи
> Enter file in which to save the key (/c/Users/grine/.ssh/id_ed25519):
- Укажите место хранения ключей. Простой вариант — сделать домашний каталог пользователя путём по умолчанию. Для этого нажмите
Enter
.
Note
Вот тут если я ввожу какой-то набор символов, например, my_new_key
, то в домашней директории появляются my_new_key
и my_new_key.pub
, а если нажимаю Enter
, как говорит практикум, то в домашней директории появляется директория .ssh/
, в которой будут ключи (видимо, с именами по умолчанию) id_ed25519
и id_ed25519.pub
- Программа запросит кодовую фразу (англ. passphrase) для доступа к SSH-ключу. Вы можете оставить поле пустым. Для этого нажмите
Enter
, а затем ещё разEnter
для подтверждения.
> Enter passphrase (empty for no passphrase): [Type a passphrase]
> Enter same passphrase again: [Type passphrase again]
Note
💡 Быть или не быть кодовой фразе — вот в чём вопрос
Как бы странно ни звучало, кодовая фраза — это «пароль от ключа». Представьте, что SSH-ключ лежит в шкатулке. А на самой шкатулке — кодовый замок, который открывается кодовой фразой.
Многие пользователи Git не используют кодовую фразу для защиты своего SSH-ключа. Если такой фразы нет, то её не нужно вводить всякий раз при взаимодействии с удалённым репозиторием.
С другой стороны, применение кодовой фразы усиливает безопасность ключей. Если вы используете эту фразу, ключ будет надёжно защищён в случае несанкционированного доступа к вашему компьютеру.
- Готово! Теперь осталось проверить, что ключи действительно сгенерировались. Для этого вызовите эту команду.
ls -a ~/.ssh
$ ls -la .ssh/
total 18
drwxr-xr-x 1 grine 197121 0 авг 29 12:04 ./
drwxr-xr-x 1 grine 197121 0 авг 29 12:03 ../
-rw-r--r-- 1 grine 197121 411 авг 29 12:04 id_ed25519
-rw-r--r-- 1 grine 197121 103 авг 29 12:04 id_ed25519.pub
[!ATTENTION] На экране должны появиться два файла — один с расширением
.pub
, другой — без. Файл в.pub
— публичный, им можно делиться с веб-сайтами или коллегами. Файл без расширения.pub
— приватный. Ни в коем случае не передавайте его никому!
- После выполнения команды
ssh-keygen
из предыдущего урока в директории~/.ssh
будет создано два файла —id_ed25519
иid_ed25519.pub
(илиid_rsa
иid_rsa.pub
— в зависимости от того, какой алгоритм вы использовали):-
id_ed25519
/id_rsa
— приватный ключ (файл без.pub
в конце). Ни в коем случае не копируйте его и не делитесь им. -
id_ed25519.pub
/id_rsa.pub
— публичный ключ (на это указывает расширение.pub
).Скопируйте содержимое файла с публичным ключом в буфер обмена.
-
macOS
# скопировать содержимое ключа в буфер обмена:
$ pbcopy < ~/.ssh/id_rsa.pub
# для ed25519:
$ pbcopy < ~/.ssh/id_ed25519.pub
Здесь используется команда pbcopy
— она копирует поток данных в буфер обмена. Запись pbcopy < ~/.ssh/id_rsa.pub
означает: «Скопируй в буфер обмена всё содержимое файла ~/.ssh/id_rsa.pub
».
Windows
# скопировать содержимое ключа в буфер обмена:
$ clip < ~/.ssh/id_rsa.pub
# для ed25519:
$ clip < ~/.ssh/id_ed25519.pub
В качестве альтернативы вы можете распечатать файл на экран с помощью cat ~/.ssh/id_rsa.pub
и скопировать его вручную.
- Перейдите на GitHub и выберите пункт Settings (англ. «настройки») в меню аккаунта (справа, сверху).
- В меню слева нажмите на пункт SSH and GPG keys.
- В открывшейся вкладке выберите New SSH key (англ. «новый SSH-ключ»).
- В поле Title (англ. «заголовок») напишите название ключа. Например, Personal key (англ. «личный ключ»).
- В поле Key type (англ. «тип ключа») должно быть Authentication Key (англ. «ключ аутентификации»).
- В поле Key скопируйте ваш ключ из буфера обмена.
- Нажмите на кнопку Add SSH key (англ. «добавить SSH-ключ»).
- Проверьте правильность ключа с помощью следующей команды.
$ ssh -T [email protected]
Если это первый раз, когда вы используете Git, чтобы поделиться проектом на GitHub, появится похожее предупреждение.
The authenticity of host 'github.com (140.82.121.4)' can't be established. ED25519 key fingerprint is SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU. This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])?
Это предупреждение сообщает, что вы никогда не соединялись с сервером GitHub. Поэтому Git не может гарантировать, что сервер является тем, за кого он себя выдаёт.
Для подтверждения подлинности сервер генерирует и публикует ключи SHA256. Вы можете проверить ключи GitHub по этой ссылке. Если ключ в предупреждении совпадает с тем, что вы видите на сайте, значит, сервер является действительным. Введите yes
, чтобы продолжить. Вы увидите приветствие на экране.
Hi %ВАШ_АККАУНТ%! You've successfully authenticated, but GitHub does not provide shell access.
- Перейдите на страницу удалённого репозитория, выберите тип
SSH
и скопируйте URL. Кнопка справа позволит сделать это мгновенно. - Откройте консоль, перейдите в каталог локального репозитория и введите команду
git remote add
(от англ. remote — «удалённый» и add — «добавить»).
$ cd <путь до локального репозитория>
$ git remote add origin [email protected]:%ИМЯ_АККАУНТА%/%НАЗВАНИЕ_РЕПОЗИТОРИЯ%.git
# чтобы отвязать локальный репозиторий от удаленного, есть такая команда
$ git remote rm origin # эта команда удалит текущий origin
Команде необходимо передать два параметра: имя удалённого репозитория и его URL. В качестве имени используйте слово origin
. А URL вы скопировали со страницы удалённого репозитория.
[!faq]
origin
(англ. «источник») — стандартный псевдоним, с помощью которого можно обращаться к главному удалённому репозиторию (обычно такой репозиторий один). Это значительно упрощает работу.
- Убеждаемся, что репозитории связаны
$ git remote -v
origin [email protected]:%ИМЯ_АККАУНТА%/%ИМЯ-ПРОЕКТА%.git (fetch)
origin [email protected]:%ИМЯ_АККАУНТА%/%ИМЯ-ПРОЕКТА%.git (push)
В выводе вы должны увидеть две строчки, аналогичные тем, что показаны выше.
Флаг -v
— короткая форма флага --verbose
(англ. «подробный»). Он позволяет показать больше информации в выводе.
[!faq] Команда
git remote add
принимает имя удалённого репозитория (или псевдонимorigin
) и его адрес.
Локальный и удалённый репозитории связаны! Теперь надо их синхронизировать.
[!faq] Каждый коммит сохраняет актуальное состояние файлов. Сами же коммиты хранятся в ветках (англ. branch).
Если коммит — это снимок состояния файлов, то ветка — временна́я шкала, на которой расположены эти снимки. Ветка всегда начинается от одного из коммитов.
Самая первая ветка в репозитории появляется автоматически и называется main
(англ. «основная») или master
. Её имя нужно указывать при отправке коммитов на удалённый репозиторий или при получении их из него.
Мы уже прошли весь «цикл коммита»: подготовили файлы с помощью git add
, закоммитили их с комментарием командой git commit -m
. Осталось загрузить содержимое локального репозитория на GitHub. За это отвечает команда git push
(от англ. push — «толкать»).
В первый раз эту команду нужно вызвать с флагом -u
и параметрами origin
(имя удалённого репозитория) и main
или master
(название текущей ветки). Флаг -u
свяжет локальную ветку с одноимённой удалённой. Как вы связывали локальный и удалённый репозитории в предыдущем уроке, так же и здесь нужно дополнительно связать ветки.
$ git push -u origin main # Если команда приведёт к ошибке, попробуйте
# заменить main на master.
[!ATTENTION] Без коммитов в репозитории эта команда не выполнится.
[!faq] 💡 Команда git push имеет несколько флагов, которые можно использовать для дополнительной настройки:
-u или --set-upstream - устанавливает отслеживание для ветки, что позволяет вам использовать git push и git pull без указания имени удаленного репозитория и названия ветки;
-f или --force - заставляет Git принудительно заменить удаленную ветку измененной локальной веткой, даже если это приведет к потере данных;
-n или --dry-run - позволяет вам протестировать команду git push, не отправляя реальных изменений в удаленный репозиторий;
-v или --verbose - выводит дополнительную информацию о процессе отправки изменений.Пример использования команды
git push
с флагом:
git push -u origin main
Эта команда отправляет изменения из вашей локальной ветки main в удаленный репозиторий с именем origin и устанавливает отслеживание для этой ветки.
При взаимодействии с удалёнными репозиториями Git выводит в консоль отладочную информацию: количество объектов (файлов), которые отправляются на сервер, информацию о прогрессе сжатия и записи и так далее.
$ git push -u origin master
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 12 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (10/10), 956 bytes | 95.00 KiB/s, done.
Total 10 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:%ИМЯ_ПОЛЬЗОВАТЕЛЯ%/%ИМЯ_РЕПОЗИТОРИЯ%.git
* [new branch] master -> master
branch 'master' set up to track 'origin/master'.
Если вы указывали кодовую фразу при настройке SSH-ключей, её нужно будет ввести.
Теперь можно зайти в репозиторий на github и убедиться, что в нем появились все коммиты и последний содержит актуальное состояние локального репозитория.
[!attention] В дальнейшем при работе с удалённым репозиторием флаг
-u
можно опустить и писать простоgit push
.
Чтобы другие пользователи, а также потенциальные клиенты или работодатели могли понять, что представляет собой проект, его нужно описать. Такое описание принято указывать в файле README.md
(от англ. read — «прочитай» и me — «меня»).
Как правило, в README.md
проекта можно найти следующую информацию:
- Название проекта и его краткое описание: кем создан, для чего, какие решает задачи и какие закрывает проблемы.
- Технологии, которые применяются в проекте. В чём его отличие от аналогичных.
- Документация проекта — подробная инструкция о том, что представляет собой проект.
- Планы проекта, если они есть.
- Инструкция, как запустить проект у себя локально на компьютере.
Вот пример файла
README.md
для Git на GitHub.
README.md
— текстовый файл, который можно создать командой touch
, а затем редактировать так же, как и любой другой текстовый документ. Например, в блокноте.
Преимущество README.md
в том, что средства командной работы (такие, как GitHub) могут отображать его содержимое в браузере в виде удобной разметки. Для этого нужно не просто залить текст, но и настроить шрифт, заголовки и отступы с помощью markdown. Маркда́ун — это специальный язык разметки. Он позволяет красиво отформатировать текстовый документ.
Информация о коммите — это набор данных: когда был сделан коммит, содержимое файлов в репозитории на момент коммита и ссылка на предыдущий, или родительский (англ. parent), коммит.
Git хеширует (преобразует) информацию о коммите и получает для каждого коммита свой уникальный хеш. Если вы знаете хеш, вы можете узнать всё остальное: автора и дату коммита и содержимое закоммиченных файлов.
Все хеши и таблицу хеш → информация о коммите
Git сохраняет в служебные файлы. Они находятся в скрытой папке .git
в репозитории проекта.
После вызова git log
появляется список коммитов. Вот так выглядит описание самого первого коммита в репозитории Git.
commit e83c5163316f89bfbde7d9ab23ca2e25604af290 # хеш коммита
Author: Linus Torvalds <[email protected]> # автор коммита
Date: Thu Apr 7 15:13:13 2005 -0700 # дата и время коммита
Initial revision of "git", the information manager from hell # сообщение к коммиту
Когда в репозитории много коммитов, удобно вызывать сокращенный лог.
$ git log --oneline
a9e32da (HEAD -> master, origin/master) Добавил README.md
2d41c56 make homework complete
0cc2241 Изменен todo.txt
3bf522a Отредактирован readme.txt
d44a27b Мой первый коммит!
Note
Команда git log --oneline
автоматически подбирает такую длину сокращённых хешей, чтобы они были уникальными в пределах репозитория и Git всегда мог понять, о каком коммите идёт речь.
При вызове команды git log
вы также можно заметить надпись (HEAD -> master)
после хеша одного из коммитов. Файл HEAD
(англ. «голова», «головной») — один из служебных файлов папки .git
. Он указывает на коммит, который сделан последним (то есть на самый новый).
$ cd .git/
$ cat HEAD
ref: refs/heads/master
$ cat HEAD # команда cat показывает содержимое файла
ref: refs/heads/master # в файле вот такая ссылка
$ cat refs/heads/master # взяли ссылку из файла HEAD
a9e32da54fa9665add1cfb5dbfc75ea25ff8d0d6 # внутри хеш
# сверяем с хешем последнего коммита
$ git log
commit a9e32da54fa9665add1cfb5dbfc75ea25ff8d0d6 (HEAD -> master, origin/master)
Author: gr_nikita <[email protected]>
Date: Wed Aug 30 15:45:54 2023 +0300
Добавил README.md
Tip
При работе с Git указатель HEAD
используется довольно часто. Мы уже упоминали, что многие команды Git принимают в качестве параметра хеш коммита. Если нужно передать последний коммит, то вместо его хеша можно просто написать слово HEAD
— Git поймёт, что вы имели в виду последний коммит.
У каждого коммита в Git есть сообщение — то, что передаётся после параметра -m
. Есть общие рекомендации по тому, как правильно составить сообщение. Оно должно быть:
- относительно коротким, чтобы его было легко прочитать;
- информативным.
Note
В плохой коммит придётся «заглядывать» — разбираться, что именно поменялось и зачем.
Причины информативности (выполняется одно или несколько одновременно):
- В сообщении есть указание на название объекта (например, имя), а также на то, какое действие с ним совершено («сделана красной»).
- В сообщении содержатся ответы на вопросы «Что добавить?» и «Куда именно?»
- Есть информация о номере ошибки и конкретизация проблемы.
- Есть необходимая информация о том, что было сделано и где.
- Сообщения к коммитам в разных стилях.
Причины неинформативности:
- Слишком общо. Непонятно, какие исправления внесены, их суть.
- Нет имен того, над чем произведены изменения.
- Нет информации о причинах изменений.
- Нет информации, где произведены изменения.
Чтобы упростить работу, команды или даже целые компании часто договариваются об определённом стиле (то есть о правилах) оформления сообщений коммитов. Например, правила могут быть такие:
- длина сообщения от 3030 до 7272 символов;
- первое слово — глагол в инфинитиве («исправить», «дополнить», «добавить» и другие);
- и так далее.
В корпоративном стиле в начале сообщения обычно указывают Jira-ID, а после — текст сообщения. LGS-239
значит, что это 239-я задача в проекте LGS (сокращение от англ. logistics — «логистика»).
$ git commit -m "LGS-239: Дополнить список пасхалок новыми числами"
Conventional Commits предлагает такой формат коммита: <type>: <сообщение>
. Первая часть type
— это тип изменений. Таких типов достаточно много. Вот два примера:
feat
(англ. «навык») — для новой функциональности;fix
(от англ. «исправить», «устранить») — для исправленных ошибок.
Более подробный список можно увидеть на сайте с описанием этого стиля.
$ git commit -m "feat: добавить подсчёт суммы заказов за неделю"
GitHub можно использовать не только для хранения файлов проекта, но и для ведения списка задач (англ. issue) этого проекта. Если коммит «закрывает» или «решает» какую-то задачу, то в его сообщении удобно указывать ссылку на неё. Для этого в любом месте сообщения нужно указать #<номер задачи>
. Например, вот так.
$ git commit -m "Исправить #334, добавить график температуры"
[!attention] 💡 Инфинитив и императив
Для сообщений на русском языке часто рекомендуют использовать инфинитивы. Например:
Добавить тесты для PipkaService
,Исправить ошибку #123
и так далее.Для сообщений на английском рекомендуется использовать повелительное наклонение (англ. imperative). Например:
Use library mega_lib_300
,Fix exit button
и так далее.Эти рекомендации сложились исторически, и им следуют многие проекты.
Иногда в только что выполненном коммите нужно что-то поменять: например, добавить ещё пару файлов или заменить сообщение на более информативное.
[!attention] 💡 Важно: опция
--amend
работает только с последним коммитом (HEAD
). Для исправления более ранних коммитов есть другие команды.
Представьте, что делаете небольшой сайт и для этого создали файл-страницу main.html
, а также файл со стилями common.css
. В какой-то момент вы забыли о файле common.css
и добавили в коммит только main.html
.
$ touch main.html && touch common.css
$ ls
common.css main.html
$ git add main.html
$ git commit -m "Добавить главную страницу"
# лог коммита
$ git log --oneline
da089fb (HEAD -> master) Добавить главную страницу
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
common.css
nothing added to commit but untracked files present (use "git add" to track)
Можно дополнить последний коммит забытым файлом common.css
с помощью опции --amend
.
$ git add common.css
$ git commit --amend --no-edit # --no-edit сообщает команде commit,
# что сообщение коммита нужно оставить как было
# лог коммита
$ git log --oneline
407c67d (HEAD -> master) Добавить главную страницу
# коммит в истории всё ещё один (но у него новый хеш)
Точно так же можно добавить не новый файл, а дополнительные изменения в уже добавленном в коммит файле.
# отредактировали main.html
$ git add main.html # добавили в список на коммит
$ git commit --amend --no-edit
Note
💡 Что же выбрать: новый коммит или --amend
?
В нашем примере вместо изменения последнего коммита можно было также выполнить новый коммит с одним файлом common.css
. Кажется, что так проще, но добавить изменения в уже существующий коммит может быть правильнее.
Например, через месяц кто-то захочет просмотреть историю изменений. Намного проще понять, что изменилось, если оба файла находятся в одном коммите. Иначе коммит со второй порцией изменений придётся искать.
Может быть и так, что добавлять новые файлы в коммит не нужно, зато понадобилось изменить сообщение.
$ git commit --amend -m "Добавить главную страницу и стили"
# лог коммита
$ git log --oneline
c4a54c3 (HEAD -> master) Добавить главную страницу и стили
# хеш коммита снова поменялся, потому что изменились сообщение и время коммита
Одна из ключевых задач Git — отслеживать изменения файлов в репозитории. Для этого каждый файл помечается каким-либо статусом. Рассмотрим основные.
- коммитов не было
$ git status
On branch master
No commits yet # коммитов еще не было
# нечего коммитить, рабочая директория чиста
nothing to commit (create/copy files and use "git add" to track)
untracked
(англ. «неотслеживаемый») Новые файлы в Git-репозитории помечаются какuntracked
, то есть неотслеживаемые. Git «видит», что такой файл существует, но не следит за изменениями в нём. Уuntracked
-файла нет предыдущих версий, зафиксированных в коммитах или через командуgit add
.
$ touch file.txt # создали новый файл в локальном репозитории
$ git status
On branch master
No commits yet # коммитов еще не было
Untracked files:
(use "git add <file>..." to include in what will be committed)
file.txt # красный, неотслеживаемый
nothing added to commit but untracked files present (use "git add" to track)
staged
(англ. «подготовленный») После выполнения командыgit add
файл попадает в staging area (от англ. stage — «сцена», «этап [процесса]» и area — «область»), то есть в список файлов, которые войдут в коммит. В этот момент файл находится в состоянииstaged
.
$ git add . # добавим неотслеживаемый ранее файл в staging area
$ git status # снова запросим состояние репозитория
On branch master
No commits yet # коммитов еще не было
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file.txt # зеленый, пока не закоммитили его, он будет 'new file'
Note
💡 Staging area, index и cache
Staging area также называют index (англ. «каталог») или cache (англ. «кеш»), а состояние файла staged
иногда называют indexed
или cached
.
Все три варианта могут встречаться в документации и в качестве флагов команд Git. А также в интернете — например, в вопросах и ответах на сайте Stack Overflow.
tracked
(англ. «отслеживаемый») Состояниеtracked
— это противоположностьuntracked
. Оно довольно широкое по смыслу: в него попадают файлы, которые уже были зафиксированы с помощьюgit commit
, а также файлы, которые были добавлены в staging area командойgit add
. То есть все файлы, в которых Git так или иначе отслеживает изменения.modified
(англ. «изменённый») Состояниеmodified
означает, что Git сравнил содержимое файла с последней сохранённой версией и нашёл отличия.
# не делаем коммит, меняем file.txt (содержимое "1")
$ git status
On branch master
No commits yet # коммитов еще не было
Changes to be committed: # если далее сделать коммит,
# будет зафиксирована эта версия содержимого
(use "git rm --cached <file>..." to unstage)
new file: file.txt # прежнее содержимое (пустой файл), зеленый
# пока не закоммитили его, он будет 'new file'
Changes not staged for commit: # чтобы закоммитить эту версию содержимого,
# надо сделать git add file.txt
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: file.txt # содержимое "1", красный
# здесь его новое воплощение, уже без 'new', так как
# он modified
$ git commit -m 'Информативное сообщение к коммиту' # делаем коммит
# лог коммита
$ git status
On branch master
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: file.txt # содержимое "1", красный
# больше он никогда не будет 'new', потому что
# был закоммичен, но будет modified, если
# его изменить
no changes added to commit (use "git add" and/or "git commit -a")
$ git add .
$ git commit -m "Еще один информативный коммит"
# лог коммита
$ git status
On branch master
nothing to commit, working tree clean
# изменили file.txt (содержимое "2")
$ git status
On branch master
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: file.txt # содержимое "2", красный
# больше он никогда не будет 'new', потому что
# был закоммичен, но будет modified, если
# его изменить
no changes added to commit (use "git add" and/or "git commit -a")
На разных этапах работы с Git могут происходить похожие ситуации:
- В список на коммит попал лишний файл (например, временный). Нужно «вынуть» его из списка.
$ touch example.txt # создали ненужный файл
$ git add example.txt # ошибочно добавили его в staged
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
# у яндекса use "git restore --staged <file>..." to unstage
new file: example.txt
$ git rm --cached example.txt
rm 'example.txt'
$ ls -la
total 12
-rw-r--r-- 1 grine 197121 0 авг 31 13:08 example.txt
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
example.txt
nothing added to commit but untracked files present (use "git add" to track)
# файл example.txt из staged вернулся обратно в untracked
Чтобы «сбросить» все файлы из staged
обратно в untracked
/modified
, можно воспользоваться командой git restore --staged .
: она сбросит всю текущую папку (.
).
- Последние несколько коммитов ошибочные: например, сделали не то, что было нужно, или нарушили логику. Хочется «откатить» сразу несколько коммитов, вернуть «как было вчера».
$ git log --oneline
ae96294 (HEAD -> master) delete file1.txt and file2.css # неудачный коммит
490f7b7 add file2.css and file3.html
228a6be add file1.txt
$ git reset --hard 490f7b7 # откатываем состояние репозитория
HEAD is now at 490f7b7 add file2.css and file3.html
$ ls -l # все файлы на месте
total 0
-rw-r--r-- 1 grine 197121 0 авг 31 13:35 file1.txt
-rw-r--r-- 1 grine 197121 0 авг 31 13:35 file2.css
-rw-r--r-- 1 grine 197121 0 авг 31 13:32 file3.html
$ git log --oneline
# коммит ae96294 Git просто удалил.
490f7b7 (HEAD -> master) add file2.css and file3.html
228a6be add file1.txt
[!ATTENTION] Будьте осторожны с командой
git reset --hard
! При удалении коммитов можно потерять что-то нужное.
- Случайно изменился файл, который вообще не должен был меняться. Например, вы открыли не тот файл в редакторе и начали его исправлять.
$ ls
forever_empty.txt
$ git status
On branch master
nothing to commit, working tree clean
$ nano forever_empty.txt # все-таки случайно файл изменили :(
$ git status
On branch master
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: forever_empty.txt
no changes added to commit (use "git add" and/or "git commit -a")
$ cat forever_empty.txt
some data # о нет, вечно пустой файл не пуст!
$ git restore forever_empty.txt
$ cat forever_empty.txt # ура, вернулось прежнее содержимое файла (пустой файл)
$ git status
On branch master
nothing to commit, working tree clean
[!NOTE] Резюме
- Команда
git restore --staged <file>
переведёт файл изstaged
обратно вmodified
илиuntracked
(короче: уберет файл из списка на коммит).- Команда
git reset --hard <commit hash>
«откатит» историю до коммита с хешем<hash>
. Более поздние коммиты потеряются (коротко: выручит, когда уже накоммитил)!- Команда
git restore <file>
«откатит» изменения в файле до последней сохранённой (в коммитеgit commit
или в staginggit add
) версии (коротко: выручит вас, если нужно откатить изменения, которые ещё не попали ни в staging area, ни в коммит).
При работе с Git часто нужно узнать, что конкретно изменится или уже изменилось после того или иного коммита. Это позволяет делать команда git diff
(от англ. difference — «отличие», «разница»).
$ touch teremok.txt # создадим теремок
$ nano teremok.txt # и зададим ему состояние
$ cat teremok.txt # состояние теремка такое
Теремок стоит, и в нём:
никого нет
$ git add .
$ git commit -m "Добавить исходное состояние теремка"
# лог коммита
$ nano teremok.txt # изменим состояние теремка
$ cat teremok.txt # новое состояние теремка
Теремок стоит, и в нём:
мышка-норушка
$ git status
On branch master
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: teremok.txt
no changes added to commit (use "git add" and/or "git commit -a")
$ git diff # Эта команда сравнит последнюю закоммиченную версию
# файла teremok.txt с текущей (изменённой) версией
# а без коммита можно сравнить с modified (индекс/staged area с modified)?
diff --git a/teremok.txt b/teremok.txt
index 0796ce6..c52685f 100644
--- a/teremok.txt
+++ b/teremok.txt
@@ -1,2 +1,2 @@
Теремок стоит, и в нём:
-никого нет
+мышка-норушка
Note
git diff
показывает изменения, которые не были добавлены в staged
.
Соответственно, посмотреть изменения с помощью git diff
можно, только если они не были проиндексированы или закоммичены.
git diff --staged
показывает, что изменилось в проиндексированных файлах.
Соответственно, ключ --staged
говорит системе, что нужно смотреть изменения, которые были добавлены в staged
.
git diff <A> <B>
показывает, что изменилось в B
, по сравнению с A
. По сути, выводит список инструкций: как превратить состояние A
в состояние B
.
Самое важное git diff
выводит в конце:
- красный цвет/минус строки
никого нет
значит, что эта строка была удалена; - зелёный цвет/плюс строки
Мышка-норушка
значит, что она была добавлена.
Коротко разберём остальные строки вывода команды:
- Первые две строки (
diff --git a/... b/...
иindex 901da07..ac459e1 100644
) — это низкоуровневая техническая информация. Мы не будем на ней останавливаться. - Строки
--- a/teremok.txt
и+++ b/teremok.txt
говорят, что дальше будет выведен результат сравнения файловa/teremok.txt
иb/teremok.txt
— исходной и текущей версий. - Строка
@@ -1,2 +1,2 @@
сообщает, какие строки файла попали в сравнение. Выражение1,2
(неважно, с плюсом или с минусом) говорит, что были использованы две строки, начиная с первой. Если бы было, например, написано+15,7
, это значило бы, что в сравнении участвуют 7 строк, начиная с 15-й. Выражение со знаком минус (-1,2
) относится к «оригинальной» версии файла (a/teremok.txt
), а со знаком плюс (+1,2
) — к «изменённой» (b/teremok.txt
).
Note
💡 Зачем вообще указывать, какие строки файла участвуют? Разве сравниваются не все строки?
Указывается не то, какие строки сравнивались, а какие попали в вывод команды git diff
. Это важно для больших файлов. Если, например, сравнить два файла по 10001000 строк, в которых отличается только 500500-я строка, то git diff
выведет порядка 1010 строк (что-нибудь вроде @@ -495,10 +495,10 @@
— с 495495-й по 505505-ю). Иначе пришлось бы читать всю тысячу. 1010 строк вместо одной нужно, чтобы было проще понять контекст изменения.
Сравнить последний коммит в локальном репозитории с секцией staged|index
(куда после git add
попадают файлы)
$ git add teremok.txt # подготовим мышку-норушку к коммиту
$ git diff # команда не выведет ничего! по умолчанию команда git diff
# не показывает изменения в staged-файлах — только в modified
$ git diff --staged
diff --git a/teremok.txt b/teremok.txt
index 0796ce6..c52685f 100644
--- a/teremok.txt
+++ b/teremok.txt
@@ -1,2 +1,2 @@
Теремок стоит, и в нём:
-никого нет
+мышка-норушка
$ git commit -m "Поселить мышку-норушку"
# лог коммита
Если вдруг на каком-то этапе работы возникнет проблема, это поможет разобраться, что конкретно изменилось в одном коммите по сравнению с другим.
$ echo "Лягушка-квакушка" >> teremok.txt
$ git add teremok.txt
$ git commit -m "Поселить лягушку-квакушку"
# пропускаем вывод команды commit
$ echo "Зайчик-побегайчик" >> teremok.txt
$ git add teremok.txt
$ git commit -m "Поселить зайчика-побегайчика"
$ echo "Лисичка-сестричка" >> teremok.txt
$ git add teremok.txt
$ git commit -m "Поселить лисичку-сестричку"
$ echo "Волчок -- серый бочок" >> teremok.txt
$ git add teremok.txt
$ git commit -m "Поселить волчка -- серого бочка"
# Пришла очередь медведя косолапого.
# Как известно, конструкция теремка не была рассчитана на массу медведя
# и теремок развалился.
# Обратите внимание на одинарный символ >
$ echo "Теремок развален" > teremok.txt
$ git add teremok.txt
$ git commit -m "Попытаться поселить медведя косолапого"
$ git log --oneline
ee142f1 (HEAD -> master) Попытаться поселить медведя косолапого
0c14016 Поселить волчка -- серого бочка
d9c5bd8 Поселить лисичку-сестричку
ce002d0 Поселить зайчика-побегайчика
f99cd73 Поселить лягушку-квакушку
bb38308 Поселить мышку-норушку
936defc Добавить исходное состояние теремка
Теперь, когда есть история коммитов, можно сравнить два коммита. Надо передать команде git diff
хеши обоих коммитов. Состояние файлов на момент первого переданного коммита будет сравниваться с состоянием файлов на момент второго.
$ git diff 936defc ee142f1 # сравнить первый и последний коммиты
diff --git a/teremok.txt b/teremok.txt
index 0796ce6..02076a5 100644
--- a/teremok.txt
+++ b/teremok.txt
@@ -1,3 +1 @@
-Теремок стоит, и в нём:
-никого нет
-
+Теремок развален
$ git diff ee142f1 936defc # сравнить последний и первый коммиты
diff --git a/teremok.txt b/teremok.txt
index 02076a5..0796ce6 100644
--- a/teremok.txt
+++ b/teremok.txt
@@ -1 +1,3 @@
-Теремок развален
+Теремок стоит, и в нём:
+никого нет
+
$ git diff HEAD 936defc # вместо ee142f1 можно подставить HEAD, результат тот же
diff --git a/teremok.txt b/teremok.txt
index 02076a5..0796ce6 100644
--- a/teremok.txt
+++ b/teremok.txt
@@ -1 +1,3 @@
-Теремок развален
+Теремок стоит, и в нём:
+никого нет
+
$ git diff f99cd73 0c14016 # кто подселялся между лягушкой-квакушкой
# и волчком — серым бочком
diff --git a/teremok.txt b/teremok.txt
index 5bd9c9c..8fef157 100644
--- a/teremok.txt
+++ b/teremok.txt
@@ -1,3 +1,6 @@
Теремок стоит, и в нём:
мышка-норушка
Лягушка-квакушка
+Зайчик-побегайчик
+Лисичка-сестричка
+Волчок -- серый бочок
Note
Чёрные строки/строки без знаков +
или -
— это «контекст», его git diff
выводит только для того, чтобы стало понятно, что находится рядом с изменёнными (зелёными и красными) строками.
Note
По сути команда git diff A B
выводит список инструкций: как превратить состояние A
в состояние B
. Если поменять A
и B
местами (git diff B A
), то и инструкции будут обратные: как превратить B
в A
. При этом все зелёные строки станут красными, и наоборот.
Чтобы Git игнорировал такие файлы и не пытался добавить их в репозиторий, нужно создать файл .gitignore
(от англ. ignore — «игнорировать») и записать в него названия игнорируемых файлов. С точки зрения Git .gitignore
— это обычный текстовый файл. Его добавляют в корень репозитория и тоже коммитят.
Note
💡 Правила из .gitignore
применяются только к новым (untracked
) файлам. Если файл уже попал в staging area или в коммит, то правила на него не распространяются.
Разберём подробнее формат файла .gitignore
, какие в нём могут встречаться строки и как выглядят шаблоны.
# с решетки начинается комментарий
.DS_Store # самое простое это написать название файла, который надо игнорировать
# в таком случае Git будет игнорировать файлы с именем .DS_Store,
# причём не только в корне репозитория, но и во всех вложенных папках.
# игнорировать все файлы, которые заканчиваются на
*.jpeg
# игнорировать все файлы "tmp" во всех подпапках папки docs
# например, Git проигнорирует файл docs/current/tmp
docs/*/tmp
# возможное правило "игнорировать все файлы"
*
# вопросительный знак ? соответствует одному любому символу
# будут проигнорированы, например, файлы fileA.txt и file1.txt
# вот файл file12.txt не будет проигнорирован
file?.txt
# квадратные скобки, как и вопросительный знак, соответствуют одному символу
# при этом символ не любой, а только из списка, который указан в скобках
# игнорировать файлы file0.txt, file1.txt и file2.txt
# при этом не игнорировать file3.txt, file4.txt, ...
file[0-2].txt
# можно либо перечислить символы ([abc]), либо задать диапазон ([a-z])
# если шаблон в .gitignore начинается со слеша, то git проигнорирует
# файлы или каталоги только в корневой директории
# игнорировать todo.txt в корне репозитория
/todo.txt
# файл todo.txt в корневом каталоге будет проигнорирован
# при этом, файл subdir/todo.txt по-прежнему отслеживается
# для сравнения: spam.txt будет игнорироваться во всех папках
spam.txt
# если шаблон заканчивается слешем, то правило применится только к папке
build/
# если build — обычный файл, то он не подпадёт под правило и не будет игнорироваться
# функция парных звёздочек (**) похожа на функцию одинарной (*)
# отличие в том, как они работают с вложенными папками: двойная звёздочка
# может соответствовать любому количеству таких папок (в том числе нулю),
# одинарная может соответствовать только одной
# игнорировать файлы "docs/current/tmp", "docs/old/tmp",
# а также "docs/old/saved/a/b/c/d/tmp"
# и даже "docs/tmp", потому что ноль вложенных папок тоже подходит
docs/**/tmp
# игнорировать только "docs/current/tmp" и "docs/old/tmp"
# файл "docs/old/saved/a/b/c/d/tmp" не попадает в правило
docs/*/tmp
# любое правило в файле .gitignore можно инвертировать с помощью восклицательного знака (!)
# игнорировать все JPEG-файлы
*.jpeg
# но только не мем с Doge
!doge.jpeg
Для примера, содержание .gitignore
может быть таким:
# игнорировать все файлы в каталоге build
build/
# игнорировать все .log файлы
*.log
# не игнорировать *.log файлы в examples
# потому что это пример для документации
!examples/**/*.log
Note
Игнорируемые файлы не отображаются в выводе команды git status
, иначе они бы засоряли вывод.
Если всё же нужно отобразить все игнорируемые файлы, то это можно сделать с помощью ключа --ignored
: git status --ignored
. В таком случае в выводе git status
появится раздел Ignored files
.
Клонирование, «форк», работа с ветками (переключение, сравнение, слияние) или как одновременно экспериментировать с проектом и сохранять стабильную версию репозитория, работая в команде.
Процесс копирования удалённого репозитория на локальный компьютер называется клонированием. Клонирование репозитория — обычно первое, что делает разработчик на новом месте работы.
Откройте консоль, перейдите в папку, в которую хотите положить репозиторий, и выполните команду git clone
(от англ. clone — «клон», «копия»). Она создаст копию удалённого репозитория на вашем компьютере. В качестве параметра команде нужно передать адрес репозитория, который вы только что скопировали на GitHub.
$ git clone [email protected]:yandex-praktikum/git-clone-lesson.git
# вывод
$ ls
... git-clone-lesson/ ...
... ... ...
Команда git clone
автоматически связывает локальный и удалённый репозиторий. То есть если в GitHub-репозитории что-то поменяется (например, добавятся коммиты), вам не нужно будет заново клонировать его. Достаточно будет выполнить команду, которая обновит вашу копию (git pull
, см. далее).
Убедитесь в том, что репозитории связаны, командой git remote -v
.
$ cd git-clone-lesson
$ git remote -v
origin [email protected]:yandex-praktikum/git-clone-lesson.git (fetch)
origin [email protected]:yandex-praktikum/git-clone-lesson.git (push)
Допустим, вы хотите усовершенствовать чужой проект, делая в нем правки и отправляя запрос на их внесение в основной код, или как-то использовать его в своей работе, но у вас нет прав на изменение оригинального репозитория.
Note
GitHub позволяет настраивать права на работу с репозиторием: кто имеет доступ к проекту, уровень доступа, права на внесение изменений и так далее. Это нужно для организации работы в проекте. Например, с помощью прав можно сделать так, чтобы только определённая группа лиц могла вносить изменения.
Fork (англ. «развилка», «ответвление»), или «форк», — это GitHub-операция; напрямую с Git она не связана. «Форк» создаёт копию репозитория в аккаунте GitHub. Такая копия будет полностью независима. Изменения, которые вы внесёте, не будут синхронизированы с исходным репозиторием.
Note
В процессе «форка» создаётся копия всех файлов, истории коммитов и веток. Эта копия сохраняется в вашей учётной записи GitHub.
Форк делается в веб-интерфейсе github. В открывшемся окне можно поменять название и описание репозитория. Можно еще поставить галку, чтобы склонировать только главную ветку вместо всех сразу.
Дальше с репозиторием можно работать как со своим. Клонировать на компьютер и вносить изменения в файлы.
Note
Обратите внимание: вам не нужно указывать флаг -u origin main
при первом git push
в форкнутый репозиторий. Команда git clone
сама свяжет удалённые и локальные ветки в момент клонирования.
Проект необязательно начинается с нуля: иногда вдохновение можно найти на просторах GitHub, но при этом решить задачу по-своему.
Например, на GitHub есть много репозиториев в формате awesome lists (англ. «потрясающие списки»). Это репозитории, в которых собраны разные полезные ссылки со всего интернета. Вот некоторые из них:
Вам пришла идея, как его ускорить код в проекте. Нужно провести эксперимент — изменить код и посмотреть, будет ли программа работать быстрее. В процессе важно скооперироваться с коллегами и ничего не сломать — в этом помогут ветки.
Note
Ветка (англ. branch) — это изолированный поток разработки проекта.
Прежде чем писать новую функциональность, для неё следует создать отдельную ветку:
- Каждый член команды может работать в своей ветке и не мешать другим
Note
Коммиты, которые он сделает, не будут видны из других веток.
- Ветки помогают декомпозировать большую и страшную задачу на маленькие и понятные.
- Ветки позволяют одному человеку переключаться между несколькими задачами сразу. Когда работа будет доделана, ветки можно соединить.
Для создания веток в Git есть команда git branch
с параметром в виде названия ветки: git branch <название_ветки>
:
# создадим тестовый репозиторий
$ mkdir git-branches && cd git-branches && git init
$ nano README.md # вносим изменения в файл
$ cat README.md
Урок: Ветки в Git
$ git add . && git commit -m "Добавить файл README"
# создадим еще одну ветку
$ git branch feature/add-branch-info
$ git branch
feature/add-branch-info
* master
Important
git branch <имя ветки>
создает новую ветку из текущей ветки.
Note
💡 Название ветки в Git может состоять из букв, цифр, а также включать любой из четырёх символов: .
, -
, _
, /
. Эти символы не несут особого смысла. Например, ветка feature/add-branch-info
могла бы называться feature_add-branch-info
или feature-add-branch
. Ветки не образуют иерархии, как директории, разделённые символом /
.
Есть разные подходы к наименованию веток. Но независимо от подхода ветки нужно называть так, чтобы другим участникам было понятно, что в них происходит.
Можно использовать указатели feature
(англ. «особенность», «деталь») для веток, где прорабатывается новая функциональность, и bugfix
(от англ. bug — «жук», «ошибка» и fix — «исправить») для веток, где ведётся работа по исправлению ошибок. После ключевого слова идёт слеш и описание проблемы или задачи (например, feature/add-gallery
).
$ git checkout feature/add-branch-info # перешли в новую ветку
Switched to branch 'feature/add-branch-info'
$ git branch # проверили
* feature/add-branch-info
master
# внесем изменения в ветке
$ nano README.md
$ cat README.md
Урок: Ветки в Git
Чтобы создать ветку, необходимо выполнить команду `git branch %BRANCH_NAME%`.
Для перехода в ветку есть команда `git checkout %BRANCH_NAME%`.
$ git add . && git commit -m "Добавить git branch и git checkout в README"
# посмотрим, что в ветке master
$ git checkout master
Switched to branch 'master'
$ cat README.md
Урок: Ветки в Git
В ветку можно перейти при создании, чтобы сразу вести в ней работу:
$ git checkout -b bugfix/fix-branch
Switched to a new branch 'bugfix/fix-branch'
$ git branch
* bugfix/fix-branch # сразу в нужной ветке
feature/add-branch-info
master
Note
💡 Ветка в Git — это указатель на коммит. Ветка указывает на коммит, который сделан в ней последним.
Когда вы делаете новый коммит в ветке, этот указатель передвигается вперёд. Пока вы не вносили новые коммиты в ветку bugfix/fix-branch
, поэтому она указывает на тот же коммит, что и основная ветка.
$ git checkout bugfix/fix-branch
$ git log --oneline
8120ac6 (HEAD -> bugfix/fix-branch, master) Добавить файл README # коммит 8120ac6
$ git checkout feature/add-branch-info
Switched to branch 'feature/add-branch-info'
$ git log --oneline
8d0e3dd (HEAD -> feature/add-branch-info) Добавить git branch и git checkout в README
8120ac6 (master, bugfix/fix-branch) Добавить файл README # коммит 8120ac6
Если у склонированного проекта есть ветки, то проект склонируется только с main
-веткой, а другие ветки локально можно так получить (в примере ветки называются change-one
и change-two
):
$ git checkout change-one
branch 'change-one' set up to track 'origin/change-one'.
Switched to a new branch 'change-one'
# создали локальную версию ветки change-one
$ git checkout change-two
branch 'change-two' set up to track 'origin/change-two'.
Switched to a new branch 'change-two'
# создали локальную версию ветки change-two
$ git checkout main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
# переключились на ветку main
Git находит два коммита, на которые указывает каждая из веток, и сравнивает их. Также с веткой можно сравнивать указатель HEAD
.
Note
💡 Файл HEAD
(англ. «голова», «головной») — один из служебных файлов папки .git
. Он указывает на последний коммит текущей ветки.
$ git checkout master
Switched to branch 'master'
$ git branch
bugfix/fix-branch
feature/add-branch-info
* master
$ nano README.md # внесем изменения в ветке
$ cat README.md
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
$ git add . && git commit -m "Добавить git branch в README"
# лог коммита
$ git checkout -b feature/diff
Switched to a new branch 'feature/diff'
$ git branch
bugfix/fix-branch
feature/add-branch-info
* feature/diff
master
$ nano README.md # внесем изменения в ветке
$ cat README.md
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
Для сравнения веток есть команда `git diff`.
$ git add . && git commit -m "Добавить git diff в README"
# лог коммита
# сравниваем ветки
$ git diff master feature/diff # сравнили ветки main и feature/diff
diff --git a/README.md b/README.md
index ab2619b..ce5a746 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
+
+Для сравнения веток есть команда `git diff`.
При сравнении вы также можете использовать название ветки и хеш коммита.
$ git log --oneline
f729bee (HEAD -> feature/diff) Добавить git diff в README
b1496df (master) Добавить git branch в README
8120ac6 (bugfix/fix-branch) Добавить файл README
$ git diff master f729bee
diff --git a/README.md b/README.md
index ab2619b..ce5a746 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
+
+Для сравнения веток есть команда `git diff`.
Для облегчения этой задачи в Git есть суффикс навигации ~N
, где N
— это число. Он отсчитывает от заданного коммита N
коммитов назад во времени. Нумерация начинается с нуля: commit~0
— это сам коммит, commit~1
— предыдущий, commit~2
— предшествующий предыдущему и так далее.
Например, HEAD~1
— это следующий за текущим коммит. А main~5
— это пятый коммит в ветке main
, если считать с последнего выполненного коммита.
На практике чаще нужен либо текущий коммит (HEAD
), либо следующий за ним (HEAD~1
). Для ~1
есть специальное сокращение ~
(без числа). То есть вместо HEAD~1
обычно пишут просто HEAD~
.
Note
💡 Также можно использовать ~0
, но большого смысла в этом нет: main~0
— это то же самое, что просто main
, а HEAD~0
— это просто HEAD
.
Можно использовать хэши коммитов, так как git diff
может сравнивать коммиты по их хэшам:
$ git log --oneline
f729bee (HEAD -> feature/diff) Добавить git diff в README
b1496df (master) Добавить git branch в README
8120ac6 (bugfix/fix-branch) Добавить файл README
$ git diff f729bee~ f729bee
diff --git a/README.md b/README.md
index ab2619b..ce5a746 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
+
+Для сравнения веток есть команда `git diff`.
Можно использовать названия веток, так как git diff
может сравнивать ветки по их названиям:
$ git diff feature/diff~1 feature/diff
diff --git a/README.md b/README.md
index ab2619b..ce5a746 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
+
+Для сравнения веток есть команда `git diff`.
Можно использовать указатель на последний коммит:
$ git diff HEAD~ HEAD
diff --git a/README.md b/README.md
index ab2619b..ce5a746 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
+
+Для сравнения веток есть команда `git diff`.
Краткий лог команд из предшествующего руководства:
$ mkdir git-branches && cd git-branches && git init
# в main
$ git add . && git commit -m "Добавить файл README"
# в feature/add-branch-info
$ git branch feature/add-branch-info
$ git checkout feature/add-branch-info
$ git add . && git commit -m "Добавить git branch и git checkout в README"
# в bugfix/fix-branch (копия main)
$ git checkout main
$ git branch bugfix/fix-branch
# в main
$ git checkout main
$ git add . && git commit -m "Добавить git branch в README"
# тут main ушла дальше своей копии в ветке bugfix/fix-branch
# в feature/diff
$ git branch feature/diff
$ git checkout feature/diff
$ git add . && git commit -m "Добавить git diff в README"
Состояние файла README.md в ветках:
$ git checkout feature/diff
Switched to branch 'feature/diff'
$ cat README.md
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
Для сравнения веток есть команда `git diff`.
$ git checkout master
Switched to branch 'master'
$ cat README.md
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
Перед тем как начать процесс слияния, нужно перейти в ветку, куда должны добавиться изменения. Обычно это главная ветка.
$ git branch
bugfix/fix-branch
feature/add-branch-info
feature/diff
* master
$ git merge feature/diff
Updating b1496df..f729bee
Fast-forward
README.md | 2 ++
1 file changed, 2 insertions(+)
$ cat README.md
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
Для сравнения веток есть команда `git diff`. # <--- строка из влитой ветки
Объединение веток прошло успешно! Все коммиты из feature/diff
добавлены в главную ветку. В сообщении после слияния содержится следующая информация:
Updating b1496df..f729bee
— значит, что коммиты cb1496df
поf729bee
были объединены.Fast-forward
— это режим слияния. Fast-forward (англ. «перемотка») значит, что итогом слияния будет линейная история коммитов. Такое происходит, когда истории двух веток находятся на одной прямой — то есть когда одна ветка продолжает историю, начатую другой, как в нашем примере.- Информация о конкретных изменениях. В нашем примере поменялся файл
README.md
(1 file changed
): в нём теперь две новые строки (2 insertions(+)
).
Основная ветка и feature/diff
теперь указывают на один коммит. Вы можете проверить это с помощью git log --oneline
.
$ git log --oneline
f729bee (HEAD -> master, feature/diff) Добавить git diff в README
b1496df Добавить git branch в README
8120ac6 (bugfix/fix-branch) Добавить файл README
После того как произошло слияние, ветку-донора можно удалить.
$ git branch # проверяем местоположение
bugfix/fix-branch
feature/add-branch-info
feature/diff
* master
$ git checkout master # если не в основной, переходим в неё
$ git branch -D feature/diff # удаляем поглощаемую ветку
Deleted branch feature/diff (was f30d441).
Ветка feature/diff
удалена — об этом говорит сообщение Deleted branch feature/diff
.
Note
can not delete branch
(англ. «не получается удалить ветку»).
У команды git branch -D
есть более безопасный вариант с флагом -d
. Он удалит ветку только если она была полностью объединена с другой — то есть если две ветки стали (или изначально были) частью одной истории. Например, если вы нечаянно создали ветку с неправильным названием, её можно удалить через git branch -d %имя_ветки%
.
Note
Когда сразу несколько членов команды работают над одним и тем же фрагментом проекта в разных ветках, при слиянии могут происходить конфликты.
Если Git не может провести слияние изменений автоматически, он сообщает о конфликте. Конфликт — это ситуация, в которой один или несколько человек модифицировали один и тот же файл. При этом результаты таких модификаций оказались несовместимы и разобраться в том, какой из вариантов правильный, может только человек.
Чтобы разобраться в ситуации, нужно сделать следующее:
- Заглянуть в файл, где произошёл конфликт.
- Изучить обе стороны конфликта — вашу версию и версию вашего коллеги. Ваша задача — правильно собрать две версии в итоговую, так чтобы изменения обеих сторон не потерялись. Новая версия станет текущей актуальной.
- Вручную удалить или подправить неактуальные изменения, если они есть.
- Подготовить изменения к сохранению и сделать коммит.
Подробнее о разрешении конфликтов можно узнать дальше в руководстве или из официальной документации Git.
Допустим, вы закончили работу над задачей в локальной ветке. Теперь хотите, чтобы эти изменения попали в основную ветку проекта и чтобы коллеги увидели результат вашей работы. Для этого вам нужно снова переместиться на GitHub.
Обычно в основной ветке на GitHub хранится актуальная версия проекта. Как правило, изменения сначала загружают в новую ветку и лишь потом вливают эту ветку в основную. Так коллеги смогут оценить ваши правки до того, как те попадут в главную ветку.
Рассмотрим, как загрузить локальную ветку в удалённый репозиторий.
Создайте на GitHub репозиторий с именем git-branches
— в него вы загрузите локальный проект git-branches
из предыдущих уроков. Сделайте его приватным, README.md можно не создавать.
Привяжем удаленный репозиторий к локальному. В качестве параметров указываются имя удалённого репозитория (origin
) и его URL:
$ git remote add origin [email protected]:ngenuine/git-branches.git
Убедитесь, что находитесь в основной ветке, и выполните команду git push
с флагом -u
, который свяжет локальную ветку с удалённой. Также команде нужно передать параметры origin
и имя текущей ветки.
$ git branch
bugfix/fix-branch
feature/add-branch-info
* master
$ git push -u origin master
Отлично! Теперь основная ветка появится на GitHub. Примерно так будет выглядеть репозиторий:
README.md Добавить git diff в README 13 minutes ago
README.md
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
Для сравнения веток есть команда `git diff`.
Теперь убедитесь, что вы находитесь в основной ветке. Если нет, перейдите в неё через git checkout main
, а затем создайте новую ветку feature/merge-request
. Откройте файл README.md
и добавьте туда строку о команде git merge
.
$ git checkout master
Already on 'master'
Your branch is up to date with 'origin/master'.
$ git checkout -b feature/merge-request
$ git branch
bugfix/fix-branch
feature/add-branch-info
* feature/merge-request
master
$ nano README.md # вносим изменения
$ cat README.md
Урок: Ветки в Git
Чтобы посмотреть все активные ветки в проекте, нужно вызвать команду `git branch` без аргументов.
Для сравнения веток есть команда `git diff`.
С помощью команды `git merge` можно слить две ветки в одну. # <--- новая строка
# добавляем изменения в staging area и делаем коммит с сообщением
$ git add . && git commit -m "Добавить merge в README"
Чтобы отправить feature/merge-request
в удалённый репозиторий, необходимо ещё раз выполнить команду push
.
[!attention] Обратите внимание: теперь необязательно переходить в ветку, чтобы запушить её.
$ git push -u origin feature/merge-request
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 403 bytes | 403.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote:
remote: Create a pull request for 'feature/merge-request' on GitHub by visiting:
remote: https://github.com/ngenuine/git-branches/pull/new/feature/merge-request
remote:
To github.com:ngenuine/git-branches.git
* [new branch] feature/merge-request -> feature/merge-request
branch 'feature/merge-request' set up to track 'origin/feature/merge-request'.
Это сообщение состоит из трёх частей:
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0
— говорит, сколько файлов было загружено. Обычно эта информация не имеет особого значения.Create a pull request for 'feature/merge-request' on GitHub by visiting:
— предоставляет ссылку, чтобы быстро создать запрос на изменения. Подробнее о таких запросах расскажем в далее.* [new branch] feature/merge-request -> feature/merge-request
— показывает, что в результате операции в удалённом репозитории была создана новая веткаfeature/merge-request
, на которую теперь ссылается локальная веткаfeature/merge-request
.
Откройте GitHub и обновите страницу. После добавления новой ветки произойдёт два события:
- вместо
1 branch
(англ. «одна ветка») станет2 branches
(англ. «две ветки»); - по клику на список веток теперь можно перейти в ветку
feature/merge-request
.
Готово! Теперь вы знаете, как загрузить любую ветку в удалённый репозиторий.
В процессе командной работы следует внимательно следить за изменениями в файлах. Нельзя просто внести правки в своей ветке и сразу залить её в основную. Сначала ваши коллеги должны убедиться, что предложенные вами изменения логичны и эффективны.
Для этого используют механизм pull request (англ. «запрос на изменения»; буквально: «запрос на подтягивание»). В обиходе его обычно так и называют — «пул-реквест», или ещё короче — ПР или PR. Алгоритм такой:
- Вы трудитесь над задачей в своей ветке — например, пишете код новой функциональности.
- Вы заканчиваете работу, а затем создаёте пул-реквест.
- Ваши коллеги проверяют, что код выглядит аккуратно и лаконично, а программа работает корректно; также оставляют комментарии. Этот процесс называют code review (англ. «рассмотрение кода»), или просто ревью.
- После финального согласования вы заливаете свою ветку в основную.
Note
Пул-реквест — это запрос на рассмотрение предлагаемых изменений и часть процесса ревью.
У каждого пул-реквеста есть:
- Название — краткое описание предлагаемых изменений. Например:
Адаптивный заголовок сайта
,Замена альбома на галерею
и так далее. - Описание — развёрнутое описание изменений. Это поле заполнять необязательно, но желательно.
- Исходная ветка — та, в которой вы работали. Например,
feature/merge-request
. - Целевая ветка — основная ветка проекта, в которую вы хотите внести изменения.
У каждого пул-реквеста может быть два исхода:
- merge (англ. «соединить») — предлагаемые изменения приняты; код вливается в целевую ветку; пул-реквест закрывается.
- close (англ. «закрыть») — пул-реквест закрывается без слияния изменений.
Note
💡 Вот тут можно посмотреть, как разработчики обсуждают изменения кода в комментариях к пул-реквесту.
Note
После того как новая ветка «запушена» в удалённый репозиторий, можно делать пул-реквест.
Существует два способа: Первый способ. При создании новой ветки в удалённом репозитории Git распечатает сообщение. Оно включает ссылку на создание пул-реквеста.
remote: Create a pull request for 'feat/diff' on GitHub by visiting:
remote: https://github.com/%ВАШ_АККАУНТ%/git-branches/pull/new/feature/merge-request
Останется только скопировать её в адресную строку браузера, заполнить необходимые поля и нажать Create pull request (англ. «создать запрос на изменения»). Многие терминалы также позволяют кликнуть на эту ссылку — напрямую или через комбинацию Cmd / Ctrl
+ клик.
Однако такая ссылка появляется только один раз и для новых веток, поэтому иногда приходится идти более сложным путём.
Второй способ. Чтобы создать пул-реквест для любой существующей ветки на GitHub, перейдите на страницу репозитория, а затем выберите вкладку Pull requests в верхней части экрана.
Выберите названия веток: ветка «откуда» (из которой будет происходить пул-реквест) и ветка «куда» (в которую он будет осуществлён). В нашем случае изменения должны попасть из ветки feature/merge-request
в ветку main
. На направление изменений указывает стрелка.
В окне ниже отобразится несколько коммитов, а также их изменения. Нажмите на кнопку Create pull request.
Note
💡 Вы можете создать пул-реквест из любой ветки, которая отличается от main
. У многих команд разработки две основные ветки. В ветке dev
ведётся вся активная работа, а в ветке main
хранится основная рабочая версия. При этом ветка dev
время от времени сливается с веткой main
.
Заполните поля с названием (например, "добавить merge в readme") и описанием (вкладка write
) пул-реквеста (например, "Описание команды merge", только побольше, ведь это развернутое описание). Нажмите Create pull request.
Готово: пул-реквест создан! Теперь вы или ваши коллеги могут перейти на вкладку Files changed (англ. «изменённые файлы»), чтобы оставить свои комментарии — провести ревью.
По окончании ревью можно посмотреть комментарии и обсудить изменения на вкладке Pull requests. Также вы можете в любой момент добавить дополнительные коммиты в ветку — они автоматически попадут в открытый пул-реквест после пуша.
Осталось только нажать на кнопку Merge pull request (англ. «принять запрос на изменения») — это действие объединит ветку с вашими изменениями и ветку main/master
.
Ура: теперь ваши изменения стали частью основной ветки!
В реальных проектах над одной программой работают как минимум два разработчика.
Представьте, что ваш коллега занимался проектом все выходные, а вы пришли в понедельник и хотите опубликовать свои правки, над которыми поработали ещё в пятницу. Однако у проекта уже новая версия — внесённые изменения есть на GitHub и на локальном компьютере коллеги, но не на вашем. В этом уроке покажем, как забрать изменения себе.
Чтобы скачать изменения из удалённого репозитория, следует выполнить команду git pull
(от англ. pull — «вытянуть») — стянуть, или «запулить» изменения.
Алгоритм такой. Сначала нужно перейти в локальный репозиторий и убедиться, что вы находитесь в правильной ветке, — как правило, это основная ветка main
(или master
). Затем можно ввести команду.
$ git pull
Обычно git pull
— это первая команда, которую вводит разработчик, как только открывает код проекта, чтобы начать с ним работать.
[!ATTENTION] Дополнительно
git pull
иgit merge
выполняют перед тем, как создать пул-реквест. При командной работе, особенно в больших командах, основная ветка часто успевает «убежать» вперёд, пока вы подготавливаете свои изменения. Поэтому перед созданием пул-реквеста рекомендуется сначала подтянуть изменения из основной ветки, объединить их с вашей, решить все возможные конфликты и лишь затем сделатьpush
.$ git checkout main # перешли в main $ git pull # подтянули новые изменения в main $ git checkout my-branch # вернулись в рабочую ветку my-branch $ git merge main # влили main в новую ветку my-branch $ git push -u origin my-branch # отправили ветку my-branch в удалённый репозиторий
git init
(от англ. initialize, «инициализировать») — инициализируй репозиторий.
git remote add origin https://github.com/YandexPracticum/first-project.git
(от англ. remote, «удалённый» + add, «добавить») — привяжи локальный репозиторий к удалённому с URL https://github.com/YandexPracticum/first-project.git
;
git remote -v
(от англ. verbose, «подробный») — проверь, что репозитории действительно связались;
git push -u origin main
(от англ. push, «толкать») — в первый раз загрузи все коммиты из локального репозитория в удалённый с названием origin
.
Note
💡 Ваша ветка может называться master
, а не main
. Подправьте команду, если это необходимо.
git push
(от англ. push, «толкать») — загрузи коммиты в удалённый репозиторий после того, как он был привязан с помощью флага -u
.
git add todo.txt
(от англ. add, «добавить») — подготовь файл todo.txt
к коммиту;
git add --all
(от англ. add, «добавить» + all, «всё») — подготовь к коммиту сразу все файлы, в которых были изменения, и все новые файлы;
git add .
— подготовь к коммиту текущую папку и все файлы в ней.
git commit -m "Комментарий к коммиту."
(от англ. commit, «совершать», фиксировать» + message, «сообщение») — сделай коммит и оставь комментарий, чтобы было проще понять, какие изменения сделаны;
git push
(от англ. push, «толкать») — добавь изменения в удалённый репозиторий.
git log
(от англ. log, «журнал [записей]») — выведи подробную историю коммитов;
git log --oneline
(от англ. log, «журнал [записей]» + oneline, «одной строкой») — покажи краткую информацию о коммитах: сокращённый хеш и сообщение.
git status
(от англ. status, «статус», «состояние») — покажи текущее состояние репозитория.
git commit --amend --no-edit
(от англ. amend, «исправить») — добавь изменения к последнему коммиту и оставь сообщение прежним;
git commit --amend -m "Новое сообщение"
— измени сообщение к последнему коммиту на Новое сообщение
.
💡 Выйти из редактора Vim: нажать Esc
, ввести :qa!
, нажать Enter
.
git restore --staged hello.txt
(от англ. restore, «восстановить») — переведи файл hello.txt
из состояния staged
обратно в untracked
или modified
;
git restore hello.txt
— верни файл hello.txt
к последней версии, которая была сохранена через git commit
или git add
;
git reset --hard b576d89
(от англ. reset, «сброс», «обнуление» + hard, «суровый») — удали все незакоммиченные изменения из staging и «рабочей зоны» вплоть до указанного коммита.
git diff
(от англ. difference, «отличие», «разница») — покажи изменения в «рабочей зоне», то есть в modified
-файлах;
git diff a9928ab 11bada1
— выведи разницу между двумя коммитами;
git diff --staged
— покажи изменения, которые добавлены в staged
-файлах.
git clone [email protected]:YandexPraktikum/first-project.git
(от англ. clone, «клон», «копия») — склонируй репозиторий с URL first-project.git
из аккаунта YandexPraktikum
на мой локальный компьютер.
git branch feature/the-finest-branch
(от англ. branch, «ветка») — создай ветку от текущей с названием feature/the-finest-branch
;
git checkout -b feature/the-finest-branch
— создай ветку feature/the-finest-branch
и сразу переключись на неё.
git branch
(от англ. branch, «ветка») — покажи, какие есть ветки в репозитории и в какой из них я нахожусь (текущая ветка будет отмечена символом *
);
git branch -a
— покажи все известные ветки, как локальные (в локальном репозитории), так и удалённые (в origin
, или на GitHub).
git checkout feature/br
— переключись на ветку feature/br
.
git diff main HEAD
(от англ. difference, «отличие», «разница») — покажи разницу между веткой main
и указателем на HEAD
;
git diff HEAD~2 HEAD
— покажи разницу между тем коммитом, который был два коммита назад, и текущим.
git branch -d br-name
— удали ветку br-name
, но только если она является частью main
;
git branch -D br-name
— удали ветку br-name
, даже если она не объединена с main
.
git merge main
(от англ. merge, «сливать», «поглощать») — объедини ветку main
с текущей активной веткой.
git push -u origin my-branch
(от англ. push, «толкнуть», «протолкнуть») — отправь новую ветку my-branch
в удалённый репозиторий и свяжи локальную ветку с удалённой, чтобы при дополнительных коммитах можно было писать просто git push
без -u
;
git push my-branch
— отправь дополнительные изменения в ветку my-branch
, которая уже существует в удалённом репозитории;
git pull
(от англ. pull, «вытянуть») — подтяни изменения текущей ветки из удалённого репозитория.