- PVSM.RU - https://www.pvsm.ru -
Предисловие [1]
1. Настройка git [2]
....1.1 Конфигурационные файлы [3]
....1.2 Настройки по умолчанию [4]
....1.3 Псевдонимы (aliases) [5]
2. Основы git [6]
....2.1 Создание репозитория [7]
....2.2 Состояние файлов [8]
....2.3 Работа с индексом [9]
....2.4 Работа с коммитами [10]
....2.5 Просмотр истории [11]
....2.6 Работа с удалённым репозиторием [12]
3. Ветвление в git [13]
....3.1 Базовые операций [14]
....3.2 Слияние веток [15]
....3.3 Rerere [16]
4. Указатели в git [17]
....4.1 Перемещение указателей [18]
5. Рекомендуемая литература [19]
Git — самая популярная распределённая система контроля версиями.[1] [20][2] [21]
Основное предназначение Git – это сохранение снимков последовательно улучшающихся состояний вашего проекта (Pro git, 2019).
Эта статья для тех, кто имеет по крайней мере базовые знания и навык работы с git и желает расширить свои знания.
Здесь рассматриваются только технические аспекты git'а, для более подробного погружения в философию git'а и его внутреннюю реализацию, советую прочитать несколько полезных книг (см. Рекомендуемая литература [19]).
Эта первая часть статьи «Введение в Git». Во второй части рассматривается работа с ветками и указателями в git.
Прежде чем начинать работу с git необходимо его настроить под себя!
Есть специальная команда
git config [<опции>]
которая позволит вам изменить стандартное поведение git, если это необходимо, но вы можете редактировать конфигурационные файлы в ручную (я считаю так быстрее).
В зависимости какой параметр вы передадите команде git config (--system, --global, --local), настройки будут записываются в один из этих файлов. Каждый из этих “уровней” (системный, глобальный, локальный) переопределяет значения предыдущего уровня!
Что бы посмотреть в каком файле, какие настройки установлены используйте git config --list --show-origin.
Игнорирование файлов
В git вы сами решаете какие файлы и в какой коммит попадут, но возможно вы бы хотели, что бы определённые файлы никогда не попали в индекс и в коммит, да и вообще не отображались в списке не отлеживаемых. Для этого вы можете создать специальный файл (.gitignore) в вашем репозитории и записать туда шаблон игнорируемых файлов. Если вы не хотите создавать такой файл в каждом репозитории вы можете определить его глобально с помощью core.excludesfile (см. Полезные настройки [22]). Вы также можете скачать готовый .gitignore file [23] для языка программирования на котором вы работаете.
Для настройки .gitignore используйте регулярные выражения bash [24].
Есть куча настроек git'а как для сервера так и для клиента, здесь будут рассмотрены только основные настройки клиента.
Используйте
git config name value
где name это название параметра, а value его значение, для того что бы задать настройки.
Пример:
git config --global core.editor nano
установит редактор по умолчанию nano.
Вы можете посмотреть значение существующего параметра с помощью git config --get [name] где name это параметр, значение которого вы хотите получить.
Полезные настройки:
Если вы не хотите печатать каждую команду для Git целиком, вы легко можете настроить псевдонимы. Для создания псевдонима используйте:
git config alias.SHORT_NAME COMMAND
где SHORT_NAME это имя для сокращения, а COMMAND команда(ы) которую нужно сократить. Пример:
git config --global alias.last 'log -1 HEAD'
после выполнения этой команды вы можете просматривать информацию о последнем коммите на текущей ветке выполнив git last.
Я советую вам использовать следующие сокращения (вы также можете определить любые свои):
Для просмотра настроек конфигурации используйте: git config --list.
Здесь перечислены только обязательные и полезные (на мой взгляд) параметры, ибо перечисление всех неуместно. Для этого используйте git command -help или --help, где command — название команды справку о который вы хотите получить.
Для просмотра состояния файлов в вашем репозитории используйте:
git status [<опции>]
Эта команда может показать вам: на какой ветке вы сейчас находитесь и состояние всех файлов. Обязательных опций нет, из полезных можно выделить разве что -s которая покажет краткое представление о состояний файлов.
Жизненный цикл файлов
Как видно на картинке файлы могут быть не отслеживаемые (Untracked) и отслеживаемые. Отслеживаемые файлы могут находится в 3 состояниях: Не изменено (Unmodifined), изменено (Modifined), подготовленное (Staged).
Если вы добавляете (с помощью git add) «Не отслеживаемый» файл, то он переходит в состояние «Подготовлено».
Если вы изменяете файл в состояния «Не изменено», то он переходит в состояние «Изменено». Если вы сохраняете изменённый файл (то есть находящийся в состоянии «Изменено») он переходит в состояние «Подготовлено». Если вы делаете коммит файла (то есть находящийся в состоянии «Подготовлено») он переходит в состояние «Не изменено».
Если версии файла в HEAD и рабочей директории отличаются, то файл будет находится в состояний «Изменено», иначе (если версия в HEAD и в рабочем каталоге одинакова") файл будет находится в состояний «Не изменено».
Если версия файла в HEAD отличается от рабочего каталога, но не отличается от версии в индексе, то файл будет в состоянии «Подготовлено».
Этот цикл можно представить следующим образом:
Unmoudifined -> Modefined -> Staged -> Unmodifined
То есть вы изменяете файл сохраняете его в индексе и делаете коммит и потом все сначала.
Надеюсь вы поняли, как выглядит жизненный цикл git репозитория. Теперь разберём как вы можете управлять индексом и файлами в вашем git репозитории.
Индекс — промежуточное место между вашим прошлым коммитом и следующим. Вы можете добавлять или удалять файлы из индекса. Когда вы делаете коммит в него попадают данные из индекса, а не из рабочей области.
Что бы просмотреть индекс, используйте git status.
Что бы добавить файлы в индекс используйте
git add [<опции>]
Полезные параметры команды git add:
Что бы удалить файлы из индекса вы можете использовать 2 команды git reset и git restore.
git-restore — восстановит файлы рабочего дерева.
git-reset — сбрасывает текущий HEAD до указанного состояния.
По сути вы можете добиться одного и того же с помощью обеих команд.
Что бы удалить из индекса некоторые файлы используйте:
git restore --staged <file>
таким образом вы восстановите ваш индекс (или точнее удалите конкретные файлы из индекса), будто бы git add после последнего коммита не выполнялся для них. С помощью этой команды вы можете восстановить и рабочую директорию, что бы она выглядела так, будто бы после коммита не выполнялось никаких изменений. Вот только эта команда имеет немного странное поведение — если вы добавили в индекс новую версию вашего файла вы не можете изменить вашу рабочую директорию, пока индекс отличается от HEAD. Поэтому вам сначала нужно восстановить ваш индекс и только потом рабочую директорию. К сожалению сделать это одной командой не возможно так как при передаче обеих аргументов (git restore -SW) не происходит ничего. И точно также при передаче -W тоже ничего не произойдет если файл в индексе и HEAD разный. Наверное, это сделали для защиты что бы вы случайно не изменили вашу рабочую директорию. Но в таком случае почему аргумент -W передаётся по умолчанию? В общем мне не понятно зачем было так сделано и для чего вообще была добавлена эта команда. По мне так reset справляется с этой задачей намного лучше, да и еще и имеет более богатый функционал так как может перемещать индекс и рабочую директорию не только на последний коммит но и на любой другой.
Но собственно разработчики рекомендуют для сброса индекса использовать именно git restore -S . Вместо git reset HEAD .
С помощью git status вы можете посмотреть какие файлы изменились но если вы также хотите узнать что именно изменилось в файлах то воспользуйтесь командой:
git diff [<options>]
таким образом выполнив команду без аргументов вы можете сравнить ваш индекс с рабочей директорией. Если вы уже добавил в индекс файлы, то используйте git diff --cached что бы посмотреть различия между последним коммитом (или тем который вы укажите) и рабочей директории. Вы также можете посмотреть различия между двумя коммитами или ветками передав их как аргумент. Пример: git diff 00656c 3d5119 покажет различия между коммитом 00656c и 3d5119.
Теперь, когда ваш индекс находится в нужном состояний, пора сделать коммит ваших изменений. Запомните, что все файлы для которых вы не выполнили git add после момента редактирования — не войдут в этот коммит. На деле файлы в нём будут, но только их старая версия (если таковая имеется).
Для того что бы сделать коммит ваших изменений используйте:
git commit [<опции>]
Полезные опции команды git commit:
Вы можете определить сообщение для коммита по умолчанию с помощью commit.template. Эта директива в конфигурационном файле отвечает за файл содержимое которого будет использоваться для коммита по умолчанию. Пример: git config --global commit.template ~/.gitmessage.txt.
Вы также можете изменить, удалить, объединить любой коммит.
Как вы уже могли заметить вы можете быстро перезаписать последний коммит с помощью git commit --amend.
Для изменения коммитом в вашей истории используйте
git rebase -i <commit>
где commit это верхний коммит в вашей цепочке с которого вы бы хотели что либо изменить.
После выполнения git rebase -i в интерактивном меню выберите что вы хотите сделать.
Для изменения сообщения определённого коммита.
Необходимо изменить pick на edit над коммитом который вы хотите изменить.
Пример: вы хотите изменить сообщение коммита 750f5ae.
pick 2748cb4 first commit
edit 750f5ae second commit
pick 716eb99 third commit
После сохранения скрипта вы вернётесь в командную строку и git скажет что необходимо делать дальше:
Остановлено на 750f5ae … second commit
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Как указанно выше необходимо выполнить git commit --amend для того что бы изменить сообщение коммита. После чего выполнить git rebase --continue. Если вы выбрали несколько коммитов для изменения названия то данные операций необходимо будет проделать над каждым коммитом.
Для удаления коммита
Необходимо удалить строку с коммитом.
Пример: вы хотите удалить коммит 750f5ae
Нужно изменить скрипт с такого:
pick 2748cb4 third commit
pick 750f5ae second commit
pick 716eb99 first commit
на такой:
pick 2748cb4 first commit
pick 716eb99 third commit
Для объединения коммитов
Необходимо изменить pick на squash над коммитами которые вы хотите объединить.
Пример: вы хотите объединить коммиты 750f5ae и 716eb99.
Необходимо изменить скрипт с такого:
pick 2748cb4 third commit
pick 750f5ae second commit
pick 716eb99 first commit
На такой
pick 2748cb4 third commit
squash 750f5ae second commit
squash 716eb99 first commit
Заметьте что в интерактивном скрипте коммиты изображены в обратном порядке нежели в git log. С помощью squash вы объедините коммит 750f5ae с 716eb99, а 750f5ae с 2748cb4. В итоге получая один коммит содержащий изменения всех трёх.
С помощью команды
git log [<опции>] [<диапазон-редакций>]
вы можете просматривать историю коммитов вашего репозитория. Есть также куча параметров для сортировки и поиска определённого коммита.
Полезные параметры команды git log:
Тагже можно отсортировать коммиты по времени, количеству и тд.
Вот несколько примеров:
git --slince=3.weeks — Покажет коммиты за последние 2 недели
git --slince=«2019-01-14» — Покажет коммиты сделанные 2019-01-14
git --slince=«2 years 1 day ago» — Покажет коммиты сделанные 2 года и один день назад.
Также вы можете настроить свои формат вывода коммитов с помощью
git log --fotmat:["format"]
.
Варианты форматирования для git log --format.
Пример:
git log --pretty=format:"%h - %ar : %s"
покажет список коммитов состоящий из хэша времени и сообщения коммита.
Так как git это распределённая СКВ вы можете работать не только с локальными но и с внешними репозиториеми.
Удалённые репозитории представляют собой версии вашего проекта, сохранённые на внешнем сервере.
Для работы с внешними репозиториями используйте:
git remote [<options>]
Если вы с клонировали репозитории через http URL то у вас уже имеется ссылка на внешний. В другом случае вы можете добавить её с помощью
git remote add [<options>] <name> <adres>
Вы можете тут же извлечь внешние ветки с помощью -f, --fetch (вы получите имена и состояние веток внешнего репозитория). Вы можете настроить репозитории только на отправку или получение данных с помощью --mirror[=(push|fetch)]. Для получения меток укажите --tags.
Для просмотра подключённых внешних репозиториев используйте git remote без аргументов или git remote -v для просмотра адресов на отправку и получение данных от репозитория.
Для отслеживания веток используйте git branch -u <rep/br> где rep это название репозитория, br название внешней ветки, а branch название локальной ветки. Либо git branch --set-upstream local_br origin/br для того что бы указать какая именно локальная ветка будет отслеживать внешнюю ветку.
Когда ваша ветка отслеживает внешнюю вы можете узнать какая ветка (локальная или внешняя) отстаёт или опережает и на сколько коммитов. К примеру если после коммита вы не выполняли git push то ваша ветка будет опережать внешнюю на 1 коммит. Вы можете узнать об этом выполнив git branch -vv, но прежде выполните git fetch [remote-name] (--all для получения обновления со всех репозиториев) что бы получить актуальные данные из внешнего репозитория. Для отмены отслеживания ветки используйте git branch --unset-upstream [<local_branch>].
Для загрузки данных с внешнего репозитория используйте git pull [rep] [branch]. Если ваши ветки отслеживают внешние, то можете не указывать их при выполнение git pull. По умолчанию вы получите данные со всех отслеживаемых веток.
Для загрузки веток на новую ветку используйте git checkout -b <new_branch_name> <rep/branch>.
Для отправки данных на сервер используйте
git push [<rep>] [<br>]
где rep это название внешнего репозитория, а br локальная ветка которую вы хотите отправить. Также вы можете использовать такую запись git push origin master:dev. Таким образом вы выгрузите вашу локальную ветку master на origin (но там она будет называется dev). Вы не сможете отправить данные во внешний репозитории если у вас нет на это прав. Также вы не сможете отправить данные на внешнюю ветку если она опережает вашу (в общем то отправить вы можете используя -f, --forse в этом случае вы перепишите историю на внешнем репозитории). Вы можете не указывать название ветки если ваша ветка отслеживает внешнюю.
Для удаления внешних веток используйте
git push origin --delete branch_name
Для получения подробной информации о внешнем репозитории (адреса для отправки и получения, на что указывает HEAD, внешние ветки, локальные ветки настроенные для git pull и локальные ссылки настроенные для git push)
git remote show <remote_name>
Для переименования названия внешнего репозитория используйте
git remote rename <last_name> <new_name>
Для удаления ссылки на внешний репозитории используйте
git remote rm <name>
Ветвление это мощные инструмент и одна из главных фич git'а поскольку позволяет вам быстро создавать и переключатся между различным ветками вашего репозитория. Главная концепция ветвления состоит в том что вы можете откланяется от основной линии разработки и продолжать работу независимо от нее, не вмешиваясь в основную линию. Ветка всегда указывает на последний коммит в ней, а HEAD указывает на текущую ветку (см. Указатели в git [17]).
Для создания ветки используйте
git branch <branch_name> [<start_commit>]
Здесь branch_name это название для новой ветки, а start_commit это коммит на который будет указывать ветка (то есть последний коммит в ней). По умолчанию ветка будет находится на последнем коммите родительской ветки.
Опции git branch:
Больше информации смотрите в git branch -h | --help.
Для переключения на ветку используйте git checkout . Также вы можете создать ветку выполнив git checkout -b <ветка>.
Для слияния 2 веток git репозитория используйте git merge .
Полезные параметры для git merge:
Процесс слияния.
Если вы не выполняли на родительской ветке новых коммитов то слияние сводится к быстрой перемотке «fast-forward», будто бы вы не создавали новую ветку, а все изменения происходили прям тут (на родительской ветке).
Если вы выполняли коммиты на обеих ветках, но при этом не создали конфликт, то слияния пройдёт в «recursive strategy», то есть вам просто нужно будет создать коммит слияния что бы применить изменения (используйте опцию --squash что бы не создавать лишний коммит).
Если вы выполняли коммиты на обоих ветках, которые внесли разные изменения в одну и ту же часть одного и того же файла, то вам придётся устранить конфликт и зафиксировать слияние коммитом.
При разрешении конфликта вам необходимо выбрать какую часть изменений из двух веток вы хотите оставить. При открытии конфликтующего файла, в нём будет содержатся следующее:
<<<<<<< HEAD
Тут будет версия изменения последнего коммита текущей ветки
======
Тут будет версия изменений последнего коммита сливаемой ветки
>>>>>>> Тут название ветки с которой сливаем
Разрешив конфликт вы должны завершить слияния выполнив коммит.
Во время конфликта вы можете посмотреть какие различия в каких файлах имеются.
git diff --ours — Разница до слияния и после
git diff --theirs — Разница сливаемой ветки до слияния и после
git diff --base — Разница с обеими ветками до слияния и после
Если вы не хотите разрешать слияние то используйте различные стратегии слияния, выбрав либо «нашу» версию (то есть ту которая находится на текущей ветке) либо выбрать «их» версию находящуюся на сливаемой ветке при этом не исправляя конфликт. Выполните git merge --Xours или git merge --Xtheirs соответственно.
Rerere — «reuse recorded resolution” — “повторное использование сохраненных разрешений конфликтов». Механизм rerere способен запомнить каким образом вы разрешали некую часть конфликта в прошлом и провести автоматическое исправление конфликта при возникновении его в следующий раз.
Что бы включить rerere выполните
git config --global rerere.enabled true
Тагже вы можите включить rerere создав каталог .git/rr-cache в нужном репозитории.
Используйте git rerere status для того что бы посмотреть для каких файлов rerere сохранил снимки состояния до начала слияния.
Используйте git rerere diff для просмотра текущего состояния конфликта.
Если во время слияния написано: Resolved 'nameFile' using previous resolution. Значит rerere уже устранил конфликт используя кэш.
Для отмены автоматического устранения конфликта используйте git checkout --conflict=merge таким образом вы отмените авто устранение конфликта и вернёте файл(ы) в состояние конфликта для ручного устранения.
в git есть такие указатели как HEAD branch. По сути всё очень просто HEAD указывает на текущую ветку, а ветка указывает на последний коммит в ней. Но для понимания лучше представлять что HEAD указывает на последний коммит.
В книге Pro git приводится очень хороший пример того как вы можете управлять вашим репозиторием поэтому я тоже буду придерживается его. Представите что Git управляет содержимым трех различных деревьев. Здесь под “деревом” понимается “набор файлов”.
В своих обычных операциях Git управляет тремя деревьями:
Собственно git предоставляет инструменты для манипулировании всеми тремя деревьями. Далее будет рассмотрена команда git reset, позволяющая работать с тремя деревьями вашего репозитория.
Используя различные опций этой команды вы можете:
Под сбросить понимается переместить на указанный коммит. По умолчанию выполняется --mixed.
Примеру 1. Вы сделали 3 лишних коммита каждый из которых приносит маленькие изменения и вы хотите сделать из них один, таким образом вы можете с помощью git reset --soft переместить указатель HEAD при этом оставив индекс и рабочий каталог нетронутым и сделать коммит. В итоге в вашей истории будет выглядеть так, что все изменения произошли в одном коммите.
Пример 2. Вы добавили в индекс лишние файлы и хотите их от туда убрать. Для этого вы можете использовать git reset HEAD <files...>. Или вы хотите что бы в коммите файлы выглядели как пару коммитов назад. Как я уже говорил ранее вы можете сбросить индекс на любой коммит в отличий от git restore который сбрасывает только до последнего коммита. Только с опцией mixed вы можете применить действие к указанному файлу!
Пример 3. Вы начали работать над новой фичей на вашем проекте, но вдруг работодатель говорит что она более не нужна и вы в порыве злости выполняете git reset --hard возвращая ваш индекс, файлы и HEAD к тому моменту когда вы ещё не начали работать над фичей. А на следующей день вам говорят, что фичу всё таки стоит запилить. Но что же делать? Как же переместится вперёд ведь вы откатили все 3 дерева и теперь в истории с помощью git log их не найти. А выход есть — это журнал ссылок git reflog. С помощью этой команды вы можете посмотреть куда указывал HEAD и переместится не только вниз по истории коммитов но и вверх. Этот журнал является локальным для каждого пользователя.
В общем думаю вы сможете придумать намного больше примеров чем я. В заключение скажу, что с помощью git reset можно творить магию…
Автор: Elliot_001
Источник [25]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/335125
Ссылки в тексте:
[1] Предисловие: #section000
[2] 1. Настройка git: #section001
[3] 1.1 Конфигурационные файлы: #section0011
[4] 1.2 Настройки по умолчанию: #section0012
[5] 1.3 Псевдонимы (aliases): #section0013
[6] 2. Основы git: #section002
[7] 2.1 Создание репозитория: #section0021
[8] 2.2 Состояние файлов: #section0022
[9] 2.3 Работа с индексом: #section0023
[10] 2.4 Работа с коммитами: #section0024
[11] 2.5 Просмотр истории: #section0025
[12] 2.6 Работа с удалённым репозиторием: #section0026
[13] 3. Ветвление в git: #section003
[14] 3.1 Базовые операций: #section0031
[15] 3.2 Слияние веток: #section0032
[16] 3.3 Rerere: #section0033
[17] 4. Указатели в git: #section004
[18] 4.1 Перемещение указателей: #section0041
[19] 5. Рекомендуемая литература: #section005
[20] [1]: https://tagline.ru/version-control-systems-rating/
[21] [2]: https://habr.com/ru/post/233935/
[22] Полезные настройки: #section_0
[23] .gitignore file: https://github.com/github/gitignore
[24] регулярные выражения bash: https://habr.com/ru/company/ruvds/blog/327896/
[25] Источник: https://habr.com/ru/post/472600/?utm_campaign=472600&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.