Шпаргалка по командам Git


Кратко про Git

Git – система контроля версий. Что-то вроде возможности сохраняться в компьютерных играх. Только более функционально. Помогает фиксировать и работать с изменениями в проекте при одиночной и командной разработке. Добавление файлов двухэтапное: сначала добавляем файл в индекс git add, потом сохраняем git commit.

Любой файл в директории существующего репозитория может быть зафиксирован или нет. То есть отслеживаться или не отслеживаться.

Отслеживаемые файлы могут быть в 3-х состояниях: неизменённые, изменённые и готовые к коммиту.

Как это работает?

Чтобы понять Git, рассмотрим концепцию трёх деревьев:

  • Рабочая директория — все файлы проекта;
  • Индекс — отслеживаемые git-ом файлы и директории, промежуточное хранилище изменений. Это редактирование и удаление отслеживаемых файлов;
  • Директория .git — всё для работы системы контроля версий. Коммиты, ветки и прочее.

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

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

Как с ним работать?

  1. Редактировать, добавлять и удалять файлы;
  2. Добавлять файлы в индекс;
  3. Делать коммит;
  4. Возврат к первому шагу.

Некоторые понятия

  • Ветка. Например, main, master, dev и т.д. — набор изменений, по сути один из набора односвязных списков;
  • HEAD — указатель на последний коммит в ветке.

Команды и флаги Git

Настройки

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

git config --global user.name "<имя>" # указать имя, которым будут подписаны коммиты
git config --global user.email "<email>"  # указать электронную почту

Если работаете в Windows:

git config --global core.autocrlf true # включить преобразование окончаний строк из CRLF в LF

Указание не отслеживаемых файлов

Файлы и директории, которые не нужно включать в репозиторий, указываются в файле .gitignore. Обычно это устанавливаемые зависимости node_modules/, venv/, готовая сборка build/ или dist/. И подобные, создаваемые при установке или запуске. Каждый файл или директория указываются с новой строки. Можно использовать генераторы.

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

git init             # создать новый репозиторий в текущей директории
git init folder-name # создать новый репозиторий в указанной директории

Клонирование репозитория

# клонировать удалённый репозиторий в одноименную директорию
git clone <ссылка на репозиторий в ssh>    

# клонировать удаленный репозиторий в директорию «FolderName»
git clone <ссылка на репозиторий в ssh> имяпапки

# клонировать репозиторий в текущую директорию
git clone <ссылка на репозиторий в ssh> .           

Добавление изменений в индекс

git add .        # добавить в индекс все новые, изменённые, удалённые файлы из текущей директории и её поддиректорий
git add text.txt # добавить в индекс указанный файл (был изменён, был удалён или это новый файл)
git add -i       # запустить интерактивную оболочку для добавления в индекс только выбранных файлов
git add -p       # показать новые/изменённые файлы по очереди с указанием их изменений и вопросом об отслеживании/индексировании

Коммиты

git commit -m "<название коммита>"  # зафиксировать в коммите проиндексированные изменения, без сообщения
git commit -am "<название коммита>" # проиндексировать отслеживаемые файлы и закоммитить, добавить сообщение

Просмотр изменений

git status              # показать состояние репозитория 
git diff                # сравнить рабочую директорию и индекс. неотслеживаемые файлы игнорируются
git diff --color-words  # сравнить рабочую директорию и индекс, показать отличия в словах. неотслеживаемые файлы игнорируются
git diff index.html     # сравнить файл из рабочей директории и индекс
git diff HEAD           # сравнить рабочую директорию и коммит, на который указывает HEAD. неотслеживаемые файлы игнорируются
git diff --staged       # сравнить индекс и коммит с HEAD
git diff main feature   # посмотреть что сделано в ветке feature по сравнению с веткой main
git diff --name-only master feature # посмотреть что сделано в ветке feature по сравнению с веткой master, показать только имена файлов
git diff master...feature # посмотреть что сделано в ветке feature с момента расхождения с main

Удаление изменений из индекса

git reset            # убрать из индекса все добавленные в него изменения. в рабочей директории все изменения сохранятся. антипод git add
git reset README.md  # убрать из индекса изменения указанного файла. в рабочей директории изменения сохранятся

Отмена изменений

git reset --hard           # опасно: отменить изменения; вернуть то, что в коммите, на который указывает HEAD (
git clean -df              # удалить неотслеживаемые изменения и директории

Отмена коммитов и перемещение по истории

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

git revert HEAD --no-edit    # создать новый коммит, отменяющий изменения последнего коммита без запуска редактора сообщения
git revert b9533bb --no-edit # то же, но отменяются изменения, внесённые коммитом с указанным хэшем b9533bb

Переключиться на другой коммит / коммиты

git checkout b9533bb # переключиться на коммит с указанным хешем
git checkout dev  # переключиться на другую ветку
git checkout -b new-branch   # создание новой ветки и переключение на неё 

Удаление файла

git rm text.txt    # удалить отслеживаемый неизменённый файл и проиндексировать это изменение
git rm -f text.txt # удалить отслеживаемый изменённый файл и проиндексировать это изменение
git rm -r log/     # удалить всё содержимое отслеживаемой директории log/ и проиндексировать это изменение
git rm ind*        # удалить все отслеживаемые файлы с именем, начинающимся на in» в текущей директории и проиндексировать это изменение
git rm --cached README.md # удалить из отслеживаемых индексированный файл. файл останется на месте. часто используется для нечаянно добавленных в индексирование файлов

История коммитов

Выход из длинного лога вывода: q, перемещения b / d / u.

git log                    # показать все изменения
git log main               # показать коммиты в указанной ветке
git log -2                 # показать последние 2 коммита в активной ветке
git log -2 --stat          # показать последние 2 коммита и статистику внесённых изменений
git log -p -22             # показать последние 22 коммита и внесённую разницу на уровне строк
git log --graph -10        # показать последние 10 коммитов с красивым ветвлением
git log --since=2.weeks    # показать коммиты за последние 2 недели
git log --after '2024-02-19' # показать коммиты, сделанные после указанной даты
git log index.html         # показать историю изменений файла index.html
git log -5 index.html      # показать историю изменений файла index.html, последние 5 коммитов 

Кто написал строку

git blame README.md --date=short -L 5,8 # показать строки 5-8 указанного файла и коммиты, в которых строки были добавлены

Ветки

git branch                 # показать список веток
git branch -v              # показать список веток и последний коммит в каждой
git branch new-branch      # создать новую ветку с указанным именем на текущем коммите
git checkout new-branch    # перейти в указанную ветку
git checkout -b new_-ranch # создать новую ветку с указанным именем и перейти в неё
git merge hotfix           # влить изменения в ветку, в которой находимся, данные из ветки hotfix
git merge hotfix --log     # влить изменения в ветку, в которой находимся, данные из ветки hotfix, показать редактор описания коммита, добавить в него сообщения вливаемых коммитов

Временное скрытие изменений без коммита

git stash     # временно сохранить незакоммиченные изменения и убрать их из рабочей директории
git stash pop # вернуть сохраненные командой git stash изменения в рабочую директорию

Удалённые репозитории

git remote -v              # показать список удалённых репозиториев, связанных с локальным
git branch -r              # показать удалённые ветки
git remote remove origin   # убрать привязку удалённого репозитория с веткой origin
git remote add origin <ссылка на репозиторий> # добавить удалённый репозиторийс указанной ссылкой на SSH
git remote rm origin       # удалить привязку удалённого репозитория
git fetch origin           # скачать все ветки с удалённого репозитория, но не сливать со своими ветками
git fetch origin main    # то же, но скачивается только указанная ветка
git push origin main     # отправить в удалённый репозиторий своей ветки main
git pull origin            # влить изменения с удалённого репозитория 

Конфликт слияния

Предполагается ситуация: есть ветка main и есть ветка feature. В обеих ветках есть коммиты, сделанные после расхождения веток. В ветку main пытаемся влить ветку feature git merge feature, получаем конфликт. Потому что в обеих ветках есть изменения одной и той же строки в файле index.html.

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

git merge feature                # влить в активную ветку изменения из ветки feature
git merge-base main feature    # показать хеш последнего общего коммита для двух указанных веток
git checkout --ours index.html   # оставить в конфликтном файле index.html состояние ветки, в которые вливаем 
git checkout --theirs index.html # оставить в конфликтном файле index.html состояние ветки, из которой мы вливаем 
git checkout --merge index.html  # показать в конфликтном файле index.html сравнение содержимого сливаемых веток для ручного редактирования
git checkout --conflict=diff3  --merge index.html # показать в конфликтном файле index.html сравнение содержимого сливаемых веток
git reset --hard  # прекратить это прерванное слияние, вернуть рабочую директорию и индекс как было в момент коммита, на который указывает HEAD. потом плакать
git reset --merge # прекратить это прерванное слияние, но оставить изменения, не закоммиченные до слияния 
git reset --abort # то же, что и строкой выше

Переносим ветки

Можно переместить ответвление какой-либо ветки от основной на произвольный коммит. Это нужно для того, чтобы в «ереносимой ветке появились какие-либо изменения, внесённые в основной ветке.

Нельзя переносить ветку, если она уже отправлена на удалённый репозиторий.

git rebase main # перенести все коммиты активной ветки так, будто активная ветка ответвилась от main. часто вызывает конфликты
git rebase --onto master feature # перенести коммиты активной ветки на main, начиная с того места, в котором активная ветка отделилась от ветки feature
git rebase --abort # прервать конфликтный rebase, вернуть рабочую директорию и индекс к состоянию до начала rebase
git rebase --continue # продолжить конфликтный rebase 

Архивирование

git archive -o ./project.zip HEAD # создать архив с файловой структурой проекта по указанному пути состояние репозитория, соответствующее указателю HEAD

Примеры

Простые и сложные примеры использования

Начало работы

Создание нового репозитория, первый коммит, привязка удалённого репозитория с gthub.com, отправка изменений в удалённый репозиторий.

# указана последовательность действий:
# директория проекта уже оздана, мы в ней
git init                      # создаём репозиторий в этой директории
touch README.md               # создаём файл README.md
git add README.md             # добавляем файл в индекс
git commit -m "first commit"  # создаём коммит
git remote add origin <ссылка на удалённый репозиторий> # добавляем предварительно созданный пустой удаленный репозиторий
git push -u origin main     # отправляем данные из локального репозитория в удалённый

Внесение изменений»в коммит

Только если коммит ещё не был отправлен в удалённые репозиторий.

# указана последовательность действий:
git add index.html       # индексируем измененный файл
git commit -m "add orange button" # делаем коммит
# Коммит пока не был отправлен в удалённый репозиторий
# Понимаем, что нужно было ещё что-то сделать в этом коммите.
# вносим изменения
git add index.html       # индексируем измененный файл
git commit --amend -m "add orange button and button handler" # заново делаем коммит

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

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

# указана последовательность действий:
git checkout -b new-feature  # создадим новую ветку для изменений
# вносим изменения
git commit -a -m "add new line" # делаем коммит
# тут выясняется, что есть баг
git checkout main             # возвращаемся к ветке main
# устраняем баг
git commit -a -m "fix bug bzzzz" # делаем коммит
git push                        # отправляем коммит в удалённый репозиторий
git checkout new-feature    # переключаемся обратно в ветку new-page-header для продолжения работ над «шапкой»
# редактируем 
git commit -a -m "add new line" # делаем коммит
git checkout master             # переключаемся в ветку main
git merge new-feature       # вливаем в master изменения из ветки new-feature
git branch -d new-feature   # удаляем ветку new-feature

Работа с ветками, конфликт слияния

Есть ветка main, в двух параллельных ветках new-feature-1 и new-feature-2 было отредактировано одно и то же место одного и того же файла, первую ветку new-feature-1 влили в main, попытка влить вторую вызывает конфликт.

# указана последовательность действий:
git checkout main           # переключаемся на ветку main
git checkout -b new-feature-1      # создаём ветку new-feature-1, основанную на ветке main
# редактируем файлы
git commit -a -m "fix №1"   # коммитим
git checkout main           # возвращаемся к ветке main
git checkout -b new-feature-2      # создаём ветку new-feature-2, основанную на ветке main
# редактируем файлы
git commit -a -m "fix №2"   # коммитим
git checkout main           # возвращаемся к ветке main
git merge new-feature-1            # вливаем изменения из ветки new-feature-1 в текущую ветку main. работает
git merge new-feature-2            # вливаем изменения из ветки new-feature-2 в текущую ветку main. конфликт
# Automatic merge failed; fix conflicts and then commit the result.
# выбираем в конфликтных файлах те участки, которые нужно оставить, сохраняем
git commit -a -m "fix conflict" # коммитим результат устранения конфликта

Синхронизация репозитория-форка с мастер-репозиторием

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

# указана последовательность действий:
git remote add upstream <ссылка на репозиторий> # добавляем удалённый репозиторий. upstream приставка для удалённых веток
git fetch upstream            # стягиваем все ветки мастер-репозитория, но пока не сливаем со своими
git checkout main           # переключаемся на ветку master своего репозитория
git merge upstream/main     # вливаем стянутую ветку master удалённого репозитория upstream в свою ветку main

Ошибка в работе: закоммитили в мастер, но поняли, что нужно было коммитить в новую ветку

Сработает только если коммит еще не отправлен в удалённый репозиторий.

# указана последовательность действий:
git checkout -b new-branch    # создаём новую ветку из main
git checkout main           # переключаемся на main
git reset HEAD~ --hard        # сдвигаем указатель main на 1 коммит назад
git checkout new-branch       # переключаемся обратно на новую и продолжаем работу

Предыдущая статья
Следующая статья

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *