2. Основы
Если у вас уже есть проект в каталоге, который не находится под версионным контролем Git, то команда git init
создаст в текущем каталоге новый подкаталог с именем .git, содержащий все необходимые файлы репозитория — структуру Git репозитория. На этом этапе ваш проект ещё не находится под версионным контролем. (добавляем файлы в индекс и коммитим)
Командой git clone
мы получим себе копию удаленного репозитория в которой будут почти все дынные из удаленного репозитория
Это важное отличие от других скв, например в svn для получения рабочей копиии репозитория используется checkout (только рабочая копия)
Таким образом в случае поломки сервера мы сможем восстановить его из любой копии репозитория (потеряются хуки, но слепки останутся)
xxxxxxxxxx
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
README
nothing added to commit but untracked files present (use "git add" to track)
Статус Untracked означает, что Git видит файл, которого не было в предыдущем снимке состояния (коммите)
Для добавления файла в индекс используется - git add <filename>
xxxxxxxxxx
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: README
Теперь файл проиндексирован, так как он находится в секции «Changes to be committed». Если вы выполните коммит в этот момент, то версия файла, существовавшая на момент выполнения вами команды git add, будет добавлена в историю снимков состояния
git add
- Это многофункциональная команда, она используется для добавления под версионный контроль новых файлов, для индексации изменений, а также для других целей, например для указания файлов с исправленным конфликтом слияния
Ситуация на скриншоте ниже наглядно демонстрирует, что Git индексирует файл в точности в том состоянии, в котором он находился, когда вы выполнили команду git add
Вы можете создать файл .gitignore. с перечислением шаблонов соответствующих таким файлам. Вот пример файла .gitignore:
xxxxxxxxxx
$ cat .gitignore
*.[oa]
*~
Первая строка предписывает Git игнорировать любые файлы заканчивающиеся на «.o» или «.a» — объектные и архивные файлы, которые могут появиться во время сборки кода. Вторая строка предписывает игнорировать все файлы заканчивающиеся на тильду (~), которая используется во многих текстовых редакторах, например Emacs, для обозначения временных файлов
Хорошая практика заключается в настройке файла .gitignore до того, как начать серьёзно работать, это защитит вас от случайного добавления в репозиторий файлов, которых вы там видеть не хотите. К шаблонам в файле .gitignore применяются следующие правила:
- Пустые строки, а также строки, начинающиеся с #, игнорируются
- Стандартные шаблоны являются глобальными и применяются рекурсивно для всего дерева каталогов
- Чтобы избежать рекурсии используйте символ слеш (/) в начале шаблона
- Чтобы исключить каталог добавьте слеш (/) в конец шаблона
- Можно инвертировать шаблон, использовав восклицательный знак (!) в качестве первого символа
Glob-шаблоны представляют собой упрощённые регулярные выражения, используемые командными интерпретаторами. Символ (*) соответствует 0 или более символам; последовательность [abc] — любому символу из указанных в скобках (в данном примере a, b или c); знак вопроса (?) соответствует одному символу; и квадратные скобки, в которые заключены символы, разделённые дефисом ([0-9]), соответствуют любому символу из интервала (в данном случае от 0 до 9). Вы также можете использовать две звёздочки, чтобы указать на вложенные каталоги: a/**/z соответствует a/z, a/b/z, a/b/c/z, и так далее
У github'a есть набор шаблонов для разных языков
https://github.com/github/gitignore
Они могут быть отправной точкой для файла .gitignore
в вашем проекте
git diff
- покажет разницу между текущим состоянием рабочего каталога и содержимым индексаgit diff --staged
- покажется разницу между последним коммитом и содержимым индекса (то есть то что войдет в коммит)
Через git difftool
можно просматривать диффы через другие утилиты (какие-то более удобные консольные или даже графические)
git commit
откроет редактор текста в котором будет предложено ввести commit-message, в нем уже будет вывод команды git status
Ключ -v
для git commit
кроме вывода git status
предварительно поместит в редактор текста еще и вывод git diff
Самой первой строкой будет пустая строка в которую и предлагается ввести свое описание коммита (git commit
&git diff
output в сам коммит не попадут, они просто позволяют сразу видеть что именно попадает в коммит чтобы можно было написать корректное описание)
Для того чтобы удалить файл из Git, вам необходимо удалить его из отслеживаемых файлов (точнее, удалить его из вашего индекса) а затем выполнить коммит. Это позволяет сделать команда git rm, которая также удаляет файл из вашего рабочего каталога, так что в следующий раз вы не увидите его как «неотслеживаемый»
Если вы изменили файл и уже проиндексировали его, вы должны использовать принудительное удаление с помощью параметра -f
. Это сделано для повышения безопасности, чтобы предотвратить ошибочное удаление данных, которые ещё не были записаны в снимок состояния и которые нельзя восстановить из Git
Чтобы удалить файл из индекса, оставив его при этом в рабочем каталоге, используйте опцию --cached
Команда
xxxxxxxxxx
$ git mv README.md README
Эквивалентна командам
xxxxxxxxxx
$ mv README.md README
$ git rm README.md
$ git add README
Полезный аргумент для git log
- -p
или --patch
, который показывает разницу (выводит патч), внесенную в каждый коммит
А если вы хотите увидеть сокращенную статистику для каждого коммита, вы можете использовать опцию --stat
Опция --pretty
принимает на вход oneline, short, medium, full, fuller, reference, email, raw, format и некоторые другие
Подробное описание форматов можно увидеть в секции PRETTY FORMATS
в git help log
format
принимает в себя строку из плейсхолдеров с помощью которой можно задать свой собственный формат
В примере ниже мы ищем коммиты которые затрагивают определенный файл и имеют в commit-message определенное слово
Если вы хотите переделать коммит — внесите необходимые изменения, добавьте их в индекс и сделайте коммит ещё раз, указав параметр --amend
:
xxxxxxxxxx
$ git commit --amend
Эта команда использует область подготовки (индекс) для внесения правок в коммит. Если вы ничего не меняли с момента последнего коммита (например, команда запущена сразу после предыдущего коммита), то снимок состояния останется в точности таким же, а всё что вы сможете изменить — это ваше сообщение к коммиту
Очень важно понимать, что когда вы вносите правки в последний коммит, вы не столько исправляете его, сколько заменяете новым, который полностью его перезаписывает. В результате всё выглядит так, будто первоначальный коммит никогда не существовал, а так же он больше не появится в истории вашего репозитория
Очевидно, смысл изменения коммитов в добавлении незначительных правок в последние коммиты и, при этом, в избежании засорения истории сообщениями вида «Ой, забыл добавить файл» или «Исправление грамматической ошибки»
Пример убирания файла из индекса
Через git add *
мы добавили лишнего, и чтобы убрать из индекса что-либо, нужно сделать git status
и в его выводе будет подсказка о том как удалить файл из индекса
git checkout -- <file>
- позволяет откатить изменения в working tree
В примере ниже мы удаляем добавленный в индекс файл (то есть делаем изменения неотслеженные гитом, вместо удаления можно просто отредактировать файл) и командой checkout
убираем эти изменения
git remote
- покажет список доступных удаленных репозиториев (ключ -v
покажет и урлы)
xxxxxxxxxx
vandud@macbook: zabbix [0] ? git remote
origin
vandud@macbook: zabbix [0] ? git remote -v
origin git@gitlab.i-free.com:puppet-modules/zabbix.git (fetch)
origin git@gitlab.i-free.com:puppet-modules/zabbix.git (push)
Чтобы добавить новый удаленный репозиторий - git remote add <shorname> <url>
git fetch
это как git pull
только другое
xxxxxxxxxx
vandud@macbook: zabbix [0] ? git fetch origin
remote: Enumerating objects: 83, done.
remote: Counting objects: 100% (83/83), done.
remote: Compressing objects: 100% (56/56), done.
remote: Total 83 (delta 36), reused 59 (delta 27)
Unpacking objects: 100% (83/83), 33.97 KiB | 644.00 KiB/s, done.
From gitlab.i-free.com:puppet-modules/zabbix
0439074..7007c2d master -> origin/master
При использовании pull, git пытается сделать всё за вас. Он сливает любые внесённые коммиты в ветку, в которой вы сейчас работаете. Команда pull автоматически сливает коммиты, не давая вам сначала просмотреть их. Если вы не пристально следите за ветками, выполнение этой команды может привести к частым конфликтам
При использовании fetch, git собирает все коммиты из целевой ветки, которых нет в текущей ветке, и сохраняет их в локальном репозитории. Однако он не сливает их в текущую ветку. Это особенно полезно, если вам нужно постоянно обновлять свой репозиторий, но вы работаете над функциональностью, неправильная реализация которой может негативно сказаться на проекте в целом. Чтобы слить коммиты в основную ветвь, нужно использовать merge
Грубо говоря, по дефолту git pull — это шоткод для последовательности двух команд: git fetch (получение изменений с сервера) и git merge (сливание в локальную копию)
Если хотите использовать поведение Git по умолчанию (простое смещение вперёд если возможно — иначе создание коммита слияния): git config --global pull.rebase "false"
Если хотите использовать перебазирование при получении изменений: git config --global pull.rebase "true"
git push <remote-name> <branch-name>
- Чтобы отправить вашу ветку master на сервер origin
git remote show <remote-name>
покажет информацию об удаленном репозитории
xxxxxxxxxx
vandud@macbook: zabbix [0] ? git remote show origin
* remote origin
Fetch URL: git@gitlab.i-free.com:puppet-modules/zabbix.git
Push URL: git@gitlab.i-free.com:puppet-modules/zabbix.git
HEAD branch: master
Remote branches:
TSUPP-3966736 tracked
UPEADM-6749 tracked
master tracked
services_exludes tracked
test tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (local out of date)
Эта команда показывает какая именно локальная ветка будет отправлена на удалённый сервер по умолчанию при выполнении git push
Она также показывает, каких веток с удалённого сервера у вас ещё нет, какие ветки всё ещё есть у вас, но уже удалены на сервере
И для нескольких веток показано, какие удалённые ветки будут в них влиты при выполнении git pull
git remote rename <oldname> <newname>
позволяет переименовать удаленный репозиторийgit remote remove <remote-name>
удаляет
xxxxxxxxxx
vandud@macbook: zabbix [0] ? git remote
origin
vandud-test-zabbix
vandud@macbook: zabbix [0] ? git remote rename vandud-test-zabbix vandud
vandud@macbook: zabbix [0] ? git remote
origin
vandud
vandud@macbook: zabbix [0] ? git remote remove vandud
vandud@macbook: zabbix [0] ? git remote
origin
git tag
Для отображение тегов. Чтобы фильтровать их согласно шаблону требуются параметры -l
или --list
Git использует два основных типа тегов: легковесные и аннотированные
Легковесный тег — это что-то очень похожее на ветку, которая не изменяется — просто указатель на определённый коммит
А вот аннотированные теги хранятся в базе данных Git как полноценные объекты. Они имеют контрольную сумму, содержат имя автора, его e-mail и дату создания, имеют комментарий и могут быть подписаны и проверены с помощью GNU Privacy Guard (GPG)
Ключ -a
создает аннотированный тэг - git tag -a v1.4 -m "my version 1.4"
git tag
без ничего создает легковесный - git tag v1.4-lw
Чтобы повесить тэг на какой-то старый коммит нужно просто указать его хэш
Было:
Вешаем тэг
xxxxxxxxxx
git tag 0.0 02800787767b7e55f9f741f65503e67727fbe5a5
Стало:
Как видно появился тэг на первом коммите
По умолчанию, команда git push не отправляет теги на удалённые сервера. После создания теги нужно отправлять явно на удалённый сервер. Процесс аналогичен отправке веток — достаточно выполнить команду git push origin <tagname>
Можно отправлять тэги по одиночке, а можно добавить опцию --tags
и отправятся все сразу
Чтобы удалить тэг у себя локально - git tag -d <tagname>
Но с сервера он так не удалится
xxxxxxxxxx
vandud@macbook: gittest [0] ? git tag | cat
0.0
0.1
vandud@macbook: gittest [0] ? git tag -d 0.0
Deleted tag '0.0' (was 0280078)
vandud@macbook: gittest [0] ? git tag | cat
0.1
Для удаления тэга в удаленном репозитории есть два путя:
xxxxxxxxxx
vandud@macbook: gittest [0] ? git push origin --delete 0.1
remote: . Processing 1 references
remote: Processed 1 references in total
To https://gitea.vandud.ru/vandud/test1.git
- [deleted] 0.1
vandud@macbook: gittest [0] ? git push origin :refs/tags/0.1-lw
remote: . Processing 1 references
remote: Processed 1 references in total
To https://gitea.vandud.ru/vandud/test1.git
- [deleted] 0.1-lw
Для перехода к тэгу - git checkout v2.0.0
Но репозиторий переходит в detached HEAD state, а это опасно
Если необходимо делать изменения в старой версии, то нужно делать отдельную ветку
xxxxxxxxxx
git checkout -b version2 v2.0.0
Можно задавать алиасы в рамках гита
xxxxxxxxxx
vandud@macbook: gittest [0] ? git config --global alias.last 'log -1 HEAD'
vandud@macbook: gittest [0] ? git last
commit 3479140973a4c5b53b20fb0a5b0fa5beef54c012
Author: Ivan Dudin <s@vandud.ru>
Date: Sun Jan 2 05:55:21 2022 +0300
commit for lightweight tag
Если вы захотите выполнить внешнюю команду, а не подкоманду Git, то следует начать команду с символа !
. Продемонстрируем этот случай на примере создания псевдонима git visual для запуска gitk:
xxxxxxxxxx
$ git config --global alias.visual '!gitk'
No Comments