Загалом, git reset
функція полягає в тому, щоб взяти поточну гілку і скинути її на точку десь в іншому місці, і, можливо, принести індекс і дерево роботи. Більш конкретно, якщо ваша головна галузь (наразі перевірена) така:
- A - B - C (HEAD, master)
і ви розумієте, що хочете, щоб майстер вказував на B, а не на C, ви будете використовувати його git reset B
для переміщення туди:
- A - B (HEAD, master) # - C is still here, but there's no branch pointing to it anymore
Відступ: Це відрізняється від каси. Якщо ви біжите git checkout B
, ви отримаєте це:
- A - B (HEAD) - C (master)
Ви опинилися в відокремленому стані HEAD. HEAD
, дерево роботи, індексувати всі збіги B
, але головна гілка залишилася в C
. Якщо ви зробите нове зобов'язання D
в цей момент, ви отримаєте це, що, мабуть, не те, що ви хочете:
- A - B - C (master)
\
D (HEAD)
Пам’ятайте, що скидання не робить зобов’язань, воно лише оновлює гілку (яка є вказівником на комісію), щоб вказувати на іншу комісію. Решта - лише деталі того, що відбувається з вашим індексом та робочим деревом.
Використовуйте випадки
Я висвітлюю багато основних випадків використання в git reset
межах своїх описів різних варіантів у наступному розділі. Його справді можна використовувати для найрізноманітніших речей; загальний потік полягає в тому, що всі вони передбачають скидання гілки, індексу та / або робочого дерева, щоб вказувати / відповідати заданій комісії.
Речі, на які слід бути обережними
--hard
може призвести до того, що ви дійсно втратите роботу. Це змінює ваше робоче дерево.
git reset [options] commit
може призвести до (втрати) зобов'язань. У наведеному вище прикладі іграшки ми втратили прихильність C
. Він все ще знаходиться в репо, і ви можете знайти його, переглянувши git reflog show HEAD
або git reflog show master
, але він фактично недоступний з жодної гілки.
Git назавжди видаляє такі зобов’язання через 30 днів, але до цього часу ви можете відновити C, знову вказуючи гілку на нього ( git checkout C; git branch <new branch name>
).
Аргументи
Перефразовуючи сторінку чоловіка, найчастіше вживається форма git reset [<commit>] [paths...]
, яка скине задані шляхи до їх стану від даної фіксації. Якщо шляхи не надані, все дерево скидається, а якщо фіксація не передбачена, вважається, що це HEAD (поточне виконання). Це поширений зразок для команд git (наприклад, checkout, diff, log, хоча точна семантика відрізняється), тому це не повинно бути занадто дивним.
Наприклад, git reset other-branch path/to/foo
скидає все в шляху / до / foo до свого стану в іншій галузі, git reset -- .
скидає поточний каталог на його стан у HEAD, а простий git reset
скидає все на його стан у HEAD.
Основні варіанти роботи дерева та параметри індексу
Існує чотири основні варіанти контролю того, що відбувається з вашим робочим деревом та індексом під час скидання.
Пам'ятайте, що індекс - це "інсценізація області" git - це те, куди йдуть справи, коли ви говорите, git add
готуючись до вчинення.
--hard
змушує все відповідати виконанню, яку ви скинули. Це найлегше зрозуміти, напевно. Усі ваші локальні зміни стають обмеженими. Одним із основних напрямків роботи є знеструмлення вашої роботи, але не перемикання зобов'язань: git reset --hard
означає git reset --hard HEAD
, тобто не змінюйте гілку, а позбавляйтеся від усіх локальних змін. Інший - просто переміщення гілки з одного місця в інше та синхронізація дерева індексу / роботи. Це той, який може насправді змусити вас втратити роботу, оскільки він модифікує ваше робоче дерево. Будьте дуже впевнені, що хочете відкинути місцеву роботу, перш ніж запустити будь-яку reset --hard
.
--mixed
є типовим, тобто git reset
засобом git reset --mixed
. Він скидає індекс, але не дерево роботи. Це означає, що всі ваші файли є неушкодженими, але будь-які відмінності між оригінальним фіксуванням та тим, до якого ви скинули, відображатимуться як локальні модифікації (або не відстежені файли) зі статусом git. Використовуйте це, коли зрозумієте, що зробили якісь погані зобов’язання, але хочете зберегти всю роботу, яку ви зробили, щоб ви могли її виправити та повторно. Для здійснення зобов’язань вам доведеться знову додати файли до індексу ( git add ...
).
--soft
не торкається індексу чи робочого дерева. Усі ваші файли є недоторканими, як і раніше --mixed
, але всі зміни відображаються як changes to be committed
зі статусом git (тобто зареєстровано під час підготовки до вчинення). Використовуйте це, коли зрозумієте, що зробили якісь погані вчинки, але робота - все добре - все, що вам потрібно зробити, - це повторити її по-іншому. Індекс недоторканий, тому ви можете скористатись негайно, якщо захочете - отримана комісія матиме той самий вміст, що і там, де ви були до скидання.
--merge
додано нещодавно і призначено допомогти вам перервати невдале злиття. Це необхідно, тому що git merge
насправді ви зможете спробувати злити з брудним робочим деревом (одне з локальними модифікаціями) до тих пір, поки ці модифікації будуть у файлах, на які не впливає злиття. git reset --merge
скидає індекс (як-от --mixed
- всі зміни відображаються як локальні модифікації) та скидає файли, на які впливає злиття, а інші залишає в спокої. Це, сподіваємось, відновить усе, як було до поганого злиття. Зазвичай ви будете використовувати його як git reset --merge
(означає git reset --merge HEAD
), оскільки ви хочете скинути злиття, а не перемістити гілку. ( HEAD
ще не оновлено, оскільки злиття не вдалося)
Якщо бути конкретнішим, припустимо, що ви змінили файли A і B, і ви намагаєтеся об'єднатись у гілку, яка модифікувала файли C і D. Злиття чомусь не вдається, і ви вирішили перервати це. Ви використовуєте git reset --merge
. Це повертає C і D до того, як вони були HEAD
, але залишає ваші модифікації A і B у спокої, оскільки вони не були частиною спроби злиття.
Хочете дізнатися більше?
Я думаю, що man git reset
це дуже добре для цього - можливо, вам потрібно трохи почуття того, як git працює для них, щоб дійсно зануритися в хоч. Зокрема, якщо ви знайдете час, щоб уважно їх прочитати, дуже корисні ці таблиці з деталізацією станів файлів в індексі та робочому дереві для всіх різних варіантів та випадків. (Але так, вони дуже щільні - вони дуже стисло передають дуже багато вищевказаної інформації.)
Дивні позначення
"Дивне позначення" ( HEAD^
і HEAD~1
), яке ви згадуєте, - це просто скорочення для вказівки комітетів, без використання хеш-імені типу 3ebe3f6
. Це повністю задокументовано в розділі "уточнення змін" сторінки man для git-rev-розбору з великою кількістю прикладів та відповідних синтаксисів. Карета і тильда насправді означають різні речі :
HEAD~
є скороченим HEAD~1
і означає першого батька вчинення. HEAD~2
означає перший з батьків перших батьків. Подумайте про те HEAD~n
, що "п позначається перед ГОЛОВОЮ" або "родоначальником п’ятого покоління ГОЛА".
HEAD^
(або HEAD^1
) також означає перший з батьків. HEAD^2
означає другий з батьків. Пам'ятайте, що у звичайній комісії злиття є два батьки - перший з батьків є об'єднаним в коміт, а другий з батьків - це об'єднання, яке було об'єднано. Взагалі злиття насправді можуть мати довільно багато батьків (злиття восьминога).
- Ці
^
та ~
оператори можуть бути нанизані, як і в HEAD~3^2
, другий батько третього покоління предка HEAD
, HEAD^^2
другий батько першого батька HEAD
, або навіть HEAD^^^
, що еквівалентно HEAD~3
.