Пошук уроків, статей та іншого контенту
Розберетеся з HEAD, хешами комітів і покажчиками, щоб звертатися до конкретних станів репозиторію.
Коміт у Git має унікальний ідентифікатор — хеш. Наприклад:
8f3a2c1d7b4e...Повний хеш може бути довгим, тому Git зазвичай дозволяє використовувати його унікальний початок:
git show 8f3a2c1Скорочений хеш працює доти, доки він однозначно визначає один коміт у поточному репозиторії. Якщо згодом з’явиться інший коміт із таким самим початком хешу, потрібно буде вказати більше символів.
Переглянути хеші комітів можна за допомогою:
git log --onelineПриклад результату:
8f3a2c1 Add validation
4b72e90 Create form
c15a8de Initial commitЛіворуч показано скорочений хеш, а праворуч — повідомлення коміту.
Гілка в Git — це покажчик на конкретний коміт. Наприклад, якщо гілка main містить останній коміт, її можна уявити так:
main ──> 8f3a2c1Коли створюється новий коміт, покажчик гілки переміщується:
c15a8de ──> 4b72e90 ──> 8f3a2c1
↑
mainHEAD — це спеціальний покажчик на поточне розташування у репозиторії. Зазвичай HEAD посилається на поточну гілку:
HEAD ──> main ──> 8f3a2c1Тому команда:
git show HEADпоказує поточний коміт, на який указує HEAD.
Перевірити значення HEAD можна так:
git rev-parse HEADЩоб побачити, на яку гілку посилається HEAD, використайте:
git symbolic-ref --short HEADЗручний загальний перегляд стану покажчиків:
git log --oneline --decorateНаприклад:
8f3a2c1 (HEAD -> main) Add validation
4b72e90 Create form
c15a8de Initial commitПозначка (HEAD -> main) означає, що HEAD посилається на гілку main, а main — на коміт 8f3a2c1.
Команда git show показує інформацію про коміт і зміни, які він містить:
git show 8f3a2c1Вона виведе:
метадані коміту;
автора;
дату;
повідомлення;
різницю між цим комітом і його батьківським комітом.
Для перегляду лише повідомлення та метаданих можна використати:
git show --no-patch 8f3a2c1Або:
git log -1 8f3a2c1Поточний коміт можна позначити як HEAD:
git show HEADПопередній коміт:
git show HEAD~1Ще один попередній коміт:
git show HEAD~2Команди HEAD~1 і HEAD^ зазвичай означають те саме:
git show HEAD^
git show HEAD~1Git має спеціальний синтаксис для переходу від одного коміту до його батьківських комітів.
^<commit>^ означає першого батька коміту:
git show HEAD^Для звичайного коміту з одним батьком це попередній коміт.
У коміту злиття може бути кілька батьків. Тоді можна вибрати конкретного:
git show HEAD^1
git show HEAD^2HEAD^1 — перший батько;
HEAD^2 — другий батько.
Це важливо під час аналізу merge-комітів.
~<commit>~n означає перехід на n поколінь назад через першого батька:
git show HEAD~1
git show HEAD~2
git show HEAD~3Для лінійної історії:
A ──> B ──> C ──> D
↑
HEADпосилання матимуть такі значення:
HEAD = D
HEAD~1 = C
HEAD~2 = B
HEAD~3 = AДля звичайних комітів ці записи еквівалентні:
HEAD^
HEAD~1Але для merge-комітів ^ також дозволяє вибрати другого батька, тоді як ~ послідовно рухається через першого батька.
Щоб порівняти поточний стан із попереднім комітом:
git diff HEAD~1 HEADЩоб порівняти два конкретні коміти:
git diff 4b72e90 8f3a2c1Щоб побачити, які зміни містить конкретний коміт, зручно використовувати:
git show 8f3a2c1Різниця між git show і git diff:
git show <commit> показує зміни, внесені одним комітом;
git diff <commit1> <commit2> порівнює два стани.
До посилання на файл у конкретному коміті додають двокрапку:
git show HEAD~1:README.mdЦя команда виведе вміст README.md таким, яким він був у попередньому коміті.
Можна вказати хеш:
git show 4b72e90:src/app.jsШлях до файлу вказується від кореня репозиторію, навіть якщо команда виконується з іншої теки.
Щоб зберегти цей вміст у робочий файл або передати його іншій команді, можна використати перенаправлення:
git show HEAD~2:config.json > config-old.jsonЦе створює або перезаписує файл config-old.json у робочій теці. Стан репозиторію та поточна гілка при цьому не змінюються.
Іноді потрібно не лише переглянути коміт, а й тимчасово зробити його поточним станом робочої теки:
git switch --detach HEAD~2Тепер HEAD безпосередньо посилається на коміт, а не на гілку:
HEAD ──> HEAD~2
main ──> найновіший комітТакий стан називається detached HEAD — «від’єднаний HEAD».
У ньому можна:
переглядати файли;
запускати програму зі старої версії;
виконувати тести;
порівнювати поведінку різних версій.
Повернутися до гілки можна так:
git switch mainЯкщо під час перебування у detached HEAD створити коміт, він не буде належати жодній гілці. Щоб не втратити цей коміт, перед створенням потрібно створити нову гілку:
git switch -c investigate-old-versionПісля цього нові коміти вже будуть належати гілці investigate-old-version.
Наведена послідовність створює невеликий репозиторій, а потім демонструє посилання на його коміти:
rm -rf git-references-demo
mkdir git-references-demo
cd git-references-demo
git init
git config user.name "Demo Developer"
git config user.email "demo@example.com"
git switch -c main
printf "version 1\n" > notes.txt
git add notes.txt
git commit -m "Create notes"
printf "version 2\n" > notes.txt
git add notes.txt
git commit -m "Update notes"
printf "version 3\n" > notes.txt
git add notes.txt
git commit -m "Finalize notes"
echo "Історія комітів:"
git log --oneline --decorate
echo "Поточний коміт:"
git rev-parse HEAD
echo "Попередня версія файлу:"
git show HEAD~1:notes.txt
echo "Зміни між двома останніми комітами:"
git diff HEAD~1 HEADПісля виконання:
HEAD посилається на третій коміт;
main також посилається на третій коміт;
HEAD~1 посилається на другий коміт;
HEAD~2 посилається на перший коміт;
git show HEAD~1:notes.txt показує рядок version 2.
Git зберігає локальну історію переміщень HEAD і гілок у reflog. Переглянути її можна так:
git reflogПриклад:
8f3a2c1 HEAD@{0}: commit: Add validation
4b72e90 HEAD@{1}: commit: Create form
c15a8de HEAD@{2}: checkout: moving from main to ...Запис виду HEAD@{1} означає попереднє значення HEAD у локальному reflog:
git show HEAD@{1}Reflog відрізняється від звичайної історії комітів:
історія комітів показує зв’язки між самими комітами;
reflog показує, як локальні покажчики змінювалися з часом.
Наприклад, після переміщення гілки або переходу між комітами reflog може допомогти знайти попередній стан HEAD.
Reflog є локальним: він не передається до віддаленого репозиторію разом із комітами.
HEAD із назвою гілкиHEAD — не обов’язково гілка. У звичайному стані він посилається на гілку:
HEAD -> mainУ detached HEAD він посилається безпосередньо на коміт:
HEAD -> 8f3a2c1HEAD~2 замість HEAD^2Ці записи мають різний сенс для merge-комітів:
HEAD^2 — другий батько поточного коміту;
HEAD~2 — два переходи через першого батька.
Скорочений хеш зручний для команд у поточному репозиторії, але він може стати неоднозначним. Для автоматизованих сценаріїв краще використовувати повний хеш або достатньо довгий унікальний префікс.
Після переходу на іншу гілку новий коміт може залишитися без покажчика. Якщо цей коміт потрібен, створіть гілку до або одразу після його створення:
git switch -c save-experimentgit show змінить файлиgit show лише показує коміт або його файл. Він не переміщує HEAD і не змінює робочу теку.
Коміт ідентифікується хешем.
Гілка — це покажчик на коміт.
HEAD указує на поточну гілку або безпосередньо на коміт у стані detached HEAD.
git show <commit> показує коміт та його зміни.
HEAD^ посилається на першого батька, а HEAD^2 — на другого батька merge-коміту.
HEAD~n переходить на n комітів назад через першого батька.
git diff <commit1> <commit2> порівнює два стани репозиторію.
git show <commit>:<path> показує файл у конкретній версії.
git switch --detach <commit> дає змогу переглянути старий стан без переміщення гілки.
git reflog показує локальну історію переміщень покажчиків.