Giter VIP home page Giter VIP logo

git-cheat-sheet's Introduction

База

Установить git

  1. Для Windows скачать и запустить Standalone Installer
  2. Для Linux
  3. Для MacOS
    1. На официальном сайте Homebrew скопировать команду и выполнить в консоли
    2. Выполнить в консоли команду brew install git

Чтобы удостовериться, что git установлен в систему, должна вылететь инфа о версии программы. Если не вылетело, значит git не установлен.

$ git --version

Прописать пользователя в git

Чтобы коммиты были от чьего-то имени, надо заполнить некоторые настройки. В консоли выполнить:

$ 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, ls

$ 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, mkdir, cp, mv

$ 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, rm -r, rmdir

$ rm example.txt # удалили файл example.txt из текущей папки
$ rmdir images # команда удалит папку images из текущей директории, 
               # если папка images пуста
$ rm -r images # удалили папку images со всем её содержимым из текущей директории

[!ATTENTION] 💡 Будьте осторожны: удаление объектов командами rm и rmdir необратимо — в этом случае файлы и папки не попадают в корзину и исчезают навсегда.

Tip

Примечание: для удаления файла используют rm, для удаления пустой директории — rmdir, а для директории с файлами — rm -r.

Чтение и редактирование файлов: cat, nano, echo, >> и >

Вывод содержимого:

$ 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.

Создание, удаление и проверка локального репозитория: init, status

$ 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 тремя способами.

$ 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>

Выполнить коммит: git commit

Ключ -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

$ git log
commit 0cc2241f3b2314760ffab951cbe10efefed154ee (HEAD -> master)
Author: user_name user_email # инфа из git config
Date:   <дата в определенном формате>

    Мой первый коммит! # сообщение к коммиту

Работа с удаленным репозиторием

[!faq] Удаленный репозиторий это не тот, который удалили. Это тот, который на GitHub.

Создать репозиторий

Надо иметь аккаунт на github, чтобы работать дальше. После регистрации заходим с главного экрана Repositories -> New -> задаем имя репозиторию и делаем его приватным или публичным -> Create repository.

SSH или как убедить github, что вы это вы, и убедиться, что github это github

[!faq] Чтобы получить доступ к репозиторию на GitHub, вам тоже нужно предоставить ключ, который подтверждает вашу личность и права на чтение или изменение данных.

Когда компьютеры обмениваются данными в сети, они следуют сетевым протоколам (англ. network protocols) — правилам обмена данными между компьютерами. Один из наиболее распространённых сетевых протоколов — SSH (от англ. Secure Shell Protocol). Он обеспечивает безопасный обмен данными в сети.

SSH использует пару ключей для обеспечения безопасности — публичный и приватный:

  • Приватный ключ (англ. private key) хранится только на вашем компьютере и не должен передаваться кому-либо ещё. Он используется для расшифровки данных.
  • Публичный ключ (англ. public key) доступен всем и используется для шифрования данных. Они могут быть расшифрованы парным приватным ключом.

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

Инструкция по генерации 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

Если папка пустая или её нет, всё в порядке. Иначе можно удалить ее, если ключи в ней не нужны. Если не удаляли, то при генерации надо будет прописать путь до нее.

Итак:

  1. Для генерации 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):
  1. Укажите место хранения ключей. Простой вариант — сделать домашний каталог пользователя путём по умолчанию. Для этого нажмите Enter.

Note

Вот тут если я ввожу какой-то набор символов, например, my_new_key, то в домашней директории появляются my_new_key и my_new_key.pub, а если нажимаю Enter, как говорит практикум, то в домашней директории появляется директория .ssh/, в которой будут ключи (видимо, с именами по умолчанию) id_ed25519 и id_ed25519.pub

  1. Программа запросит кодовую фразу (англ. passphrase) для доступа к SSH-ключу. Вы можете оставить поле пустым. Для этого нажмите Enter, а затем ещё раз Enter для подтверждения.
> Enter passphrase (empty for no passphrase): [Type a passphrase]
> Enter same passphrase again: [Type passphrase again]

Note

💡 Быть или не быть кодовой фразе — вот в чём вопрос

Как бы странно ни звучало, кодовая фраза — это «пароль от ключа». Представьте, что SSH-ключ лежит в шкатулке. А на самой шкатулке — кодовый замок, который открывается кодовой фразой.

Многие пользователи Git не используют кодовую фразу для защиты своего SSH-ключа. Если такой фразы нет, то её не нужно вводить всякий раз при взаимодействии с удалённым репозиторием.

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

  1. Готово! Теперь осталось проверить, что ключи действительно сгенерировались. Для этого вызовите эту команду.
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-ключа к github

  1. После выполнения команды 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 и скопировать его вручную.

  1. Перейдите на GitHub и выберите пункт Settings (англ. «настройки») в меню аккаунта (справа, сверху).
  2. В меню слева нажмите на пункт SSH and GPG keys.
  3. В открывшейся вкладке выберите New SSH key (англ. «новый SSH-ключ»).
  4. В поле Title (англ. «заголовок») напишите название ключа. Например, Personal key (англ. «личный ключ»).
  5. В поле Key type (англ. «тип ключа») должно быть Authentication Key (англ. «ключ аутентификации»).
  6. В поле Key скопируйте ваш ключ из буфера обмена.
  7. Нажмите на кнопку Add SSH key (англ. «добавить SSH-ключ»).
  8. Проверьте правильность ключа с помощью следующей команды.

Если это первый раз, когда вы используете 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.

Связываем локальный и удаленный репозитории

  1. Перейдите на страницу удалённого репозитория, выберите тип SSH и скопируйте URL. Кнопка справа позволит сделать это мгновенно.
  2. Откройте консоль, перейдите в каталог локального репозитория и введите команду git remote add (от англ. remote — «удалённый» и add — «добавить»).
$ cd <путь до локального репозитория>
$ git remote add origin [email protected]:%ИМЯ_АККАУНТА%/%НАЗВАНИЕ_РЕПОЗИТОРИЯ%.git

# чтобы отвязать локальный репозиторий от удаленного, есть такая команда
$ git remote rm origin # эта команда удалит текущий origin

Команде необходимо передать два параметра: имя удалённого репозитория и его URL. В качестве имени используйте слово origin. А URL вы скопировали со страницы удалённого репозитория.

[!faq] origin (англ. «источник») — стандартный псевдоним, с помощью которого можно обращаться к главному удалённому репозиторию (обычно такой репозиторий один). Это значительно упрощает работу.

  1. Убеждаемся, что репозитории связаны
$ 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

Чтобы другие пользователи, а также потенциальные клиенты или работодатели могли понять, что представляет собой проект, его нужно описать. Такое описание принято указывать в файле README.md (от англ. read — «прочитай» и me — «меня»).

Как правило, в README.md проекта можно найти следующую информацию:

  1. Название проекта и его краткое описание: кем создан, для чего, какие решает задачи и какие закрывает проблемы.
  2. Технологии, которые применяются в проекте. В чём его отличие от аналогичных.
  3. Документация проекта — подробная инструкция о том, что представляет собой проект.
  4. Планы проекта, если они есть.
  5. Инструкция, как запустить проект у себя локально на компьютере. Вот пример файла 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 — отслеживать изменения файлов в репозитории. Для этого каждый файл помечается каким-либо статусом. Рассмотрим основные.

  • коммитов не было
$ 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 или в staging git add) версии (коротко: выручит вас, если нужно откатить изменения, которые ещё не попали ни в staging area, ни в коммит).

Сравнить коммиты

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

Сравнить последний коммит в локальном репозитории с секцией modified

$ 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 (англ. «потрясающие списки»). Это репозитории, в которых собраны разные полезные ссылки со всего интернета. Вот некоторые из них:

Просмотреть ветки проекта: git branch

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

Note

Ветка (англ. branch) — это изолированный поток разработки проекта.

Прежде чем писать новую функциональность, для неё следует создать отдельную ветку:

  • Каждый член команды может работать в своей ветке и не мешать другим

Note

Коммиты, которые он сделает, не будут видны из других веток.

  • Ветки помогают декомпозировать большую и страшную задачу на маленькие и понятные.
  • Ветки позволяют одному человеку переключаться между несколькими задачами сразу. Когда работа будет доделана, ветки можно соединить.

Создать ветку: git branch <название_ветки>

Для создания веток в 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 <название_ветки>

$ 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 diff <название_ветки1> <название_ветки2>

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`.

Слияние веток: git merge <название_ветки>

Краткий лог команд из предшествующего руководства:

$ 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 — значит, что коммиты c b1496df по 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 -D <название_ветки>

После того как произошло слияние, ветку-донора можно удалить.

$ 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

⚠️ Если в момент удаления вы будете находиться в той ветке, которую хотите удалить, Git сообщит об ошибке: can not delete branch (англ. «не получается удалить ветку»).

У команды git branch -D есть более безопасный вариант с флагом -d. Он удалит ветку только если она была полностью объединена с другой — то есть если две ветки стали (или изначально были) частью одной истории. Например, если вы нечаянно создали ветку с неправильным названием, её можно удалить через git branch -d %имя_ветки%.

Note

⚠️ Удаление локальной ветки через Git не удаляет ветку на GitHub!

Конфликты при слиянии веток

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

Если Git не может провести слияние изменений автоматически, он сообщает о конфликте. Конфликт — это ситуация, в которой один или несколько человек модифицировали один и тот же файл. При этом результаты таких модификаций оказались несовместимы и разобраться в том, какой из вариантов правильный, может только человек.

Чтобы разобраться в ситуации, нужно сделать следующее:

  1. Заглянуть в файл, где произошёл конфликт.
  2. Изучить обе стороны конфликта — вашу версию и версию вашего коллеги. Ваша задача — правильно собрать две версии в итоговую, так чтобы изменения обеих сторон не потерялись. Новая версия станет текущей актуальной.
  3. Вручную удалить или подправить неактуальные изменения, если они есть.
  4. Подготовить изменения к сохранению и сделать коммит.

Подробнее о разрешении конфликтов можно узнать дальше в руководстве или из официальной документации Git.

Работа с ветками в удаленном репозитории

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

Обычно в основной ветке на GitHub хранится актуальная версия проекта. Как правило, изменения сначала загружают в новую ветку и лишь потом вливают эту ветку в основную. Так коллеги смогут оценить ваши правки до того, как те попадут в главную ветку.

Рассмотрим, как загрузить локальную ветку в удалённый репозиторий.

Отправить локальную ветку в удалённый репозиторий: git push

Создайте на 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

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

Для этого используют механизм pull request (англ. «запрос на изменения»; буквально: «запрос на подтягивание»). В обиходе его обычно так и называют — «пул-реквест», или ещё короче — ПР или PR. Алгоритм такой:

  1. Вы трудитесь над задачей в своей ветке — например, пишете код новой функциональности.
  2. Вы заканчиваете работу, а затем создаёте пул-реквест.
  3. Ваши коллеги проверяют, что код выглядит аккуратно и лаконично, а программа работает корректно; также оставляют комментарии. Этот процесс называют code review (англ. «рассмотрение кода»), или просто ревью.
  4. После финального согласования вы заливаете свою ветку в основную.

Note

Пул-реквест — это запрос на рассмотрение предлагаемых изменений и часть процесса ревью.

Из чего состоит pull request и чем он может обернуться

У каждого пул-реквеста есть:

  • Название — краткое описание предлагаемых изменений. Например: Адаптивный заголовок сайта, Замена альбома на галерею и так далее.
  • Описание — развёрнутое описание изменений. Это поле заполнять необязательно, но желательно.
  • Исходная ветка — та, в которой вы работали. Например, feature/merge-request.
  • Целевая ветка — основная ветка проекта, в которую вы хотите внести изменения.

У каждого пул-реквеста может быть два исхода:

  • merge (англ. «соединить») предлагаемые изменения приняты; код вливается в целевую ветку; пул-реквест закрывается.
  • close (англ. «закрыть») — пул-реквест закрывается без слияния изменений.

Note

💡 Вот тут можно посмотреть, как разработчики обсуждают изменения кода в комментариях к пул-реквесту.

Делаем pull request

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.

Ура: теперь ваши изменения стали частью основной ветки!

Забрать изменения из удалённого репозитория: git pull

В реальных проектах над одной программой работают как минимум два разработчика.

Представьте, что ваш коллега занимался проектом все выходные, а вы пришли в понедельник и хотите опубликовать свои правки, над которыми поработали ещё в пятницу. Однако у проекта уже новая версия — внесённые изменения есть на 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, «вытянуть») — подтяни изменения текущей ветки из удалённого репозитория.

git-cheat-sheet's People

Contributors

ngenuine avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.