https://git-scm.com/ – тут крутые entry видео, документация и прочее.
VCS
VCS позволяют не только сохранять историю кода, но и конфигов, template да и в целом любых текстовых файлов. Это нельзя забывать никогда - пригодится по жизни во многих местах.
Помимо возможности просмотра предыдущих версий файлов (не только текстовых) VCS позволяют:
- track changes (what, when, who, why)
- rollbacks
- pull requests – очень крутая штука
Если более детально:
- посмотреть когда файл был изменен
- посмотреть кто внес изменения в какой файл
- посмотреть что поменялось
- посмотреть комменты к изменениям (commit)
- можно вносить изменения в несколько файлов как одно изменение (commit changeset)
- позволяет легко откатить изменения (rollback)
- позволяет одновременную работу нескольких кодеров над одним проектом
Git
- Для удобства работы в git с подсветкой статусов в командной строке можно использовать скрипт. Процесс установки прост – копируем репозиторий в домашнюю папку, в bashrc добавляем строку со ссылкой на скрипт из репозитория и перезапускаем bash для принятия изменений. Процесс расписан тут:
https://pyneng.github.io/docs/git-basics/ cd ~ git clone https://github.com/magicmonty/bash-git-prompt.git .bash-git-prompt --depth=1 GIT_PROMPT_ONLY_IN_REPO=1 source ~/.bash-git-prompt/gitprompt.sh exec bash
Git является бесплатным open source VCS. Может быть установлен на Unix-based, Windows, OSX. Git был создан Linus Torvalds, создателем Linux, изначально как VCS для кода ядра Linux. На сайте https://git.kernel.org/ можно посмотреть как он используется при программировании ядра. А тут можно посмотреть коммиты самого Torvalds.
- нет необходимости работы клиента с каким то единым сервером
- копия кода репозитория (клон), над которой производится работа, всегда находится локально на машине
- можно установить Git на одном ПК, даже без интернет подключения этого ПК
- ничто не мешает установить Git на сервере, а остальными цепляться к этому серверу как клиентами для получения актуальных данных репозитория, отправки туда изменений (обычно так и происходит)
- в git config можно указать даже pgp/gpg ключ для подписи коммитов
- взаимодействие между Git клиентами и серверами может быть на основе HTTP, SSH или специального протокола Git.
Файлы в Git могут находиться в стадиях:
- неотслеживаемые (untracked) – не добавленные в репозиторий (git add) или удаленные файлы, по умолчанию все новые файлы в этом состоянии
- немодифицированные (unmodified) – отслеживаемые, файлы после commit
- модификация (modified) – это новый файл или сделаны изменения в старом, но он еще не закоммичен (не применен commit)
- подготовленные (staged) – файлы, поставленные на commit (добавленные в следующий commit)
- подтвержденные (commited) – срез (snapshot) файла сохранен в базе
Каждый Git проект имеет три секции:
- Рабочее дерево (working tree) – тут проводятся модификации над файлами, тут обычно находятся последние версии файлов (modified files)
- Область подготовки (staging area/index) – тут сохраняются подготовленные файлы (staged files)
Директория Git (Git directory) – по сути база твоего проекта. Тут сохраняются все snapshot проекта. Git в результате commit сохраняет в Git директории не просто разницу между предыдущим состоянием и текущим (diff), а полностью файлы. (commited files)
Commit представляет собой по сути snapshot файлов, которые были поставлены на commit. В комментариях к commit нужно указывать нужную информацию о причинах commit, например номера тикетов или ссылок на документы, rfc, переписки и прочее. Если коммит длинный – то комментарий к commit не нужно указывать непосредственно в cli, а просто ввести commit. Тогда откроется текстовый редактор, в нем первой строкой краткое описание, а далее подробный текст изменения. Есть даже сайт посвященный стилю commit https://commit.style/.
When you commit a snapshot to your repository, Git is doing which of the following?
Recording the entire contents of every file that you've changed and is part of the commit
Commit идентифицируется ID в виде HASH, расчитанного по алгоритму SHA1. Hash сделан чтобы можно было сравнивать что данные которые ты внес соответствуют данным, которые сохранены т.к. любое изменение данных приводит к изменению hash этих данных. Git ругнеться если hash от данных не будет соответсвовать hash commit. Изменение может быть безобидным – сетевая проблема, проблема с диском, но и намеренным внедрением (mitm). При использовании в командах можно указывать только первые символы hash, а не весь hash, git найдет нужный commit по вхождению в hash (обычно достаточно всего первых 4 символов).
HEAD – индикатор текущего commit для текущего branch в репозитории (по сути за ним скрывается ID текущего commit), что-то типо закладки для отслеживания местоположения (используется в командах git reset, diff, branch, status).
Github
Github – бесплатный web-based сервер репозиториев на основе git. Предоставляет доп. плюшки в виде wiki, bug tracking, task management. Бесплатен только если проект (репозиторий) публичен, если нужен приватный репозиторий – заплати денег, хотя и не много. GitHub является крупнейшим веб-сервисом для хостинга IT-проектов и их совместной разработки. Основан на системе контроля версий Git и разработан на Ruby on Rails и Erlang. Проекты можно выгружать через git clone или даже в zip. Есть аналоги – BitBucket, Gitlab. Github куплен microsoft.
Команды
Базовая работа и команды
Узнать версию
git --version
Указание username и почты (чтобы размечать тебя в commit в публичных репозиториях). В git config можно указать даже pgp/gpg ключ для подписи коммитов.
git config --global user.name "Petr Redkin"
git config --global user.email "petr@redkin.net"
git config --global core.editor vim
Смотрим конфиг
git config -l
Инициализация нового проекта (создает автоматически директорию, эмулируя mkdir “myproject”, папку не обязательно указывать – тогда это будет .git в текущей)
git init |myproject|
Переходим в директорию с проектом (тут будут файлы самого проекта и файлы, которые хранят изменения в файлах проекта)
cd myproject
Добавляем элемент или всю папку в hold на commit (переводим модифицированный файл в commit, добавляем новый файл в tracked и переводим его в commit – проставляем на файлы staged статус)
git add |-p| index.html git add * git add .
Убираем элемент или всю папку из staging area
git reset HEAD|commit_hash_id sw
Можно удалять и перемещать файлы в репозитории – говорим Git не отслеживать файл, удаляем/перемещаем его из Git directory. Файл уходит в staged, поэтому нужно сделать commit для завершения удаления/перемещения.
git rm sw
git mv sw new_dir/
GITIGNORE
Через файл .gitignore мы говорим Git не отслеживать определенные файлы. Полезно если коммит делается через *. Есть рекомендации что включать в этот файл.
vi .gitignore
*.exe # ignore compiled files
*.rar # ignore archive files
Полезно часто просто игнорировать все файлы кроме python-скриптов (или исполняемых файлов другого языка, который нужен).
https://stackoverflow.com/questions/987142/make-gitignore-ignore-everything-except-a-few-files # Ignore everything * # But not these files... !.gitignore !*.py
COMMIT
Делаем commit – создаем snapshot с данными.
-m – добавляем коммент прямо из консоли. По style так писать нежелательно, но в целом так делают даже в кратком review на сайте Git 🙂 Как по мне если изменение минорное – очень полезная вещь.
-a – автоматически добавляет все файлы, которые отслеживаются (находяться в репозитории Git) на commit (нет необходимости делать git add, если только это не новый файл)
git commit |-a| |-m "Imporing all the code"|
Перезаписть последний commit новым (удаление старого commit, все что в текущий момент в staging area будет закоммичено). Можно использовать не только когда сменились данные, но и когда нужно только поправить комментарий. Время commit будет равно времени изначального commit, а не времени amend, все остальные данные будут перезаписаны (коммент, id). Крайне нежелательно использовать для публичных commit, вместо этого нужно использовать revert.
git commit --amend
Восстановить или откатить
Чтобы восстановить конкретный файл из последнего commit, новый файл еще не в staging area (после изменения или удаления ДО применения add/rm на новую версию файла)
git checkout -- deleted_file.rb
Чтобы восстановить конкретный файл из последнего commit, новый файл уже в staging area (после изменения или удаления И применения add/rm на новую версию файла)
git reset HEAD|commit_hash_id deleted_file.rb
git checkout -- deleted_file.rb
Откат текущего состояния на определенный commit делается через checkout.
git checkout `commit-id`
Откат изменений, внесенных определенным commit делается через revert. Revert делает новый коммит, который отменяет все изменения, сделанные в указанном коммите (HEAD – в последнем коммите или commit_hash_id, можно указать не полностью) – т.е. если строка была добавлена, то в результате revert эта строка будет удалена. Таким образом можно посмотреть что было не так в “плохом” commit после отката.
git revert HEAD|commit_hash_id
Сравнение и Логи
Статус файлов, в каком состоянии они находятся
git status
Логи
git log
Опции:
-p – показать что поменялось в файлах между текущим и предыдущим commit,
-2 – показать только два последних commit,
git log -2
–decorate – добавление информации о branch, в какой branch сейчас смотрит HEAD или проще говоря для какого branch в логах показаны commit
–stat – просмотр какие файлы поменялись
origin/master – можно указать удаленный repo и branch, для которого будут показаны логи
git log |--graph --decorate --abbrev-commit --all --pretty=oneline|
git diff dc3009ec74733
git diff e15f6fe92b0c dc3009ec7473
BRANCHING AND MERGING
Branch – указатель на определенный commit. Каждый branch указывает на отдельную линию разработки в проекте. Master – branch по умолчанию, создаваемый при инициализации Git. Принято его считать и использовать как основную, production или known-good, ветку проекта. При изменениях проекта, например добавления новой фичи делается еще один branch, на основе которого происходит работа, без необходимости изменения production ветки. Branch’и позволяют очень легко экспериментировать с новыми идеями в проекте и используются повседневно. Основной профит branch состоит в том, что они не хранят и не копируют данные, они просто указывают на определенный commit.
Показать все branch в репозитории, звездой помечается в каком ты сейчас находишься
git branch
Создаем branch на основе текущего branch (не обязательно master)
git branch branch_name
Для переключения между branch’ами нужно использовать checkout, в результате команды 1) working tree изменяется с предыдущего branch на последний новый, т.е. меняются файлы в соответствии с branch 2) HEAD указывает на последний commit в новом branch, а не в старом 3) меняется commit history т.к. она ведется для branch
git checkout branch_name
Можно создать branch и сразу переключиться в него через checkout
git checkout -b branch_name
Удаление branch (ругнеться если есть неза’commit’енные в master изменения в удаляемом branch)
git branch -d branch_name
Соединяем данные и history log branch с текущим branch. Git использует два алгоритма для merge:
- fast-forward – когда branch, из которого взяты обновления, имеет все commit текущего branch (история commit между branch не отличается, один просто имеет свежие данные). В таком случае git просто переносит указатель HEAD на основе merging branch (накатывает все commit из нового branch в текущий) и по сути нет никакого merging.
- three-way-merge – когда branch, из которого взяты обновления, не имеет все commit текущего branch. т.е. в текущем branch были изменения после того как сделана копия данных (если говорить о master branch). В таком случае Git найдет самый последний commit, который совпадает между branch и будет делать merge различающихся commit’ов branch’ей после этого шага. В случае конфликтов (изменение одного региона одного файла), это называется merge conflict, Git об этом скажет. В таком случае можно использовать git status для просмотра конфликтных файлов и далее открыть сами конфликтные файлы, чтобы увидеть какие данные являются конфликтными. После разрешения конфликта (изменения необходимых строк в файле) нужно использовать git add на этот файл и сделать commit – все, конфликт разрешен.
git merge branch_name
Сбросить процедуру merge, если конфликты слишком сложные, чтобы их быстро разрешить. Данные в working tree будут восстановлены на основе текущего branch, не включая конфликты. При использовании –hard все незакомиченные изменения в текущем branch будут сброшены!
git reset --hard
КОЛЛАБОРАЦИЯ
Основные команды:
- git push – отправить на сервер изменения в локальном репозитории после commit. Git push делается после локального коммита. Настроенные remote (настраиваются автоматически при использовании git clone) позволяют это делать одной командой.
- git merge – соединение твоей копии репозитория с основной на сервере.
Админ репозитория
git checkout master
git commit -a -m "my new logo"
git push
Обычный пользователь, ответственный за какую то ветку (branch)
git checkout -b dana
git commit -a -m "my new code"
git push origin dana
Админ после этого собирает к себе на комп (git pull) и объединяет изменения последних коммитов в репозитории (git merge), с вопросами какие изменения сохранить в случае наличия конфликтов и прочим
git pull git merge dana
УДАЛЕННЫЕ РЕПОЗИТОРИИ (github)
- На github удобно diff смотреть – есть режим просмотра unified (последовательно origin – версия до изменения и change – версия после изменения) и split (на одной стороне экрана origin, на второй change – как по мне, удобнее классической) .
git clone – копируем удаленный репозиторий для локального использования (используется вместо git init, остальные команды все аналогичные, до тех пор пока не понадобится обновить удаленный репозиторий – там нужно добавить в обычной последовательности действий push). Репозиторий будет скопирован и будет иметь имя по умолчанию origin.
-
- Git clone возможен по ssh или https. В первом случае можно аутентифицироваться по ключу (и паролю), во втором по логину и паролю.
- Git clone можно сделать для последней версии repo, а можно с указанием конкретной определенной версии (по tag и/или branch) репозитория. Альтернативный путь получить код не последней версии – загрузить последнюю и делать checkout на нужную версию.
git clone https://github.com/1111/some_repo.git git clone https://github.com/pmcgleenon/wireplay.git #LATEST-VER git clone https://github.com/cisco-system-traffic-generator/trex-core.git #SPECIFIC-VER git clone https://github.com/cisco-system-traffic-generator/trex-core.git -b v2.89
Вместо создания клона можно создать связь с удаленным репозиторием. Можно использовать HTTP (обычно только RO доступ к repo), HTTPS, SSH, Git. Связь автоматически создается при использовании git clone.
git remote add origin https://github.com/paulboone/ticgit
Просмотреть все связи с удаленными репозиториями (-v показывает URL и какой будет использовать для fetch from repo и push to repo, обычно один и тот же)
git remote |-v|
Переименовка
git remote rename origin new-origin
Удаление
git remote rm origin
git pull – получаем изменения из repo. Обновление данных локального репозитория на основе удаленного. Git автоматически это не делает. Например, когда на работу пришел и нужно получить изменения, запушенные в репозиторий из дома. Команда которая делает одновременно fetch из remote repo (url shortcut) и merge на основе удаленного repo. По умолчанию branch определяется на основе текущего branch, но можно поменять. Перед git pull можно посмотреть что изменилось в repo с помощью команды git diff HEAD..origin
git pull origin |master|
git push – Обновляем удаленный репозиторий изменениями (всеми snapshot после всех commit), которые мы сделали. Нужно указать и repo (url shortcut) и branch. Git сервер скорей всего спросит username/password перед апдейтом. При использовании -all будут переданы все branch текущего репозитория. В случае конфликтов Git скажет что нужно сначала получить актуальный репозиторий через git pull, сделать merge локально (автоматически вызывается при использовании pull), а потом загружать.
git push origin master
get push --all origin
git fetch – получаем данные из удаленного репозитория в локальный как remote branch. Для получения конкретной ветки можно указать эту ветку. git branch -r смотрим такие ветки в нашем репозитории. Такие branch можно только просмотривать, не изменять.
git fetch origin |master|
git branch -r
git merge – обновляем данные нашего репозитория на основе данных удаленного.
git merge origin/master
Fork для изменения без прав + pull request для запроса на редактирование основной ветки