Яка різниця між "git reset" та "git checkout"?


440

Я завжди думав git resetі git checkoutяк про одне і те саме, в тому сенсі, що обидва повертають проект до певної віддачі. Однак я відчуваю, що вони не можуть бути абсолютно однаковими, оскільки це було б зайвим. Яка фактична різниця між ними? Я трохи розгублений, оскільки svn svn coповинен лише повернути фіксацію.

ДОБАВЛЕНО

VonC та Чарльз пояснили відмінності між git resetі git checkoutсправді добре. Моє сьогоднішнє розуміння полягає в тому, що git resetповертає всі зміни до певного зобов'язання, тоді як git checkoutбільш-менш готується до галузі. Наступні дві схеми я вважаю досить корисними для розуміння цього:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

ДОДАТО 3

З http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html , замовлення та скидання можуть імітувати ребазу.

введіть тут опис зображення

git checkout bar 
git reset --hard newbar 
git branch -d newbar 

введіть тут опис зображення



Re: "Це неправильно чи надмірно спрощено?" Так, ця перша діаграма вводить в оману щодо різниці між замовленням та скиданням. (Це може бути нормально щодо -- filesваріантів; я не впевнений.) Ця діаграма дозволяє виглядати основною різницею, чи впливають вони на індекс чи WD. Дивіться мою відповідь щодо цього. 2 та 3 діаграми дуже корисні для бачення реальної різниці. Четверта та п'ята діаграми корисні для того, щоб перевірити, чи розумієте ви, що роблять ці команди, але насправді не допоможуть вам дістатися.
LarsH

Я знайшов розділ "Перевірте це" в "Git Tools Reset Demystified", щоб дати найбільш корисну інформацію.
Йосія Йодер

1
prosseek: Якщо ви погоджуєтесь з @LarsH, що перша діаграма вводить в оману, чи можете ви її видалити, будь ласка?
Йосія Йодер

Зауважте, що перевірка та скидання імітують лише другу частину ребазу, і необхідні додаткові кроки (надані у зв’язаній think-like-a-git.netстатті), щоб запобігти втраті даних.
ковбасник

Відповіді:


198
  • git resetйдеться саме про оновлення індексу , переміщення HEAD.
  • git checkoutйдеться про оновлення робочого дерева (до індексу або вказаного дерева). Він оновлює ГОЛОВУ лише у тому випадку, якщо ви зареєструєте відділення (якщо ні, то ви отримаєте від'єднану ГОЛОВУ ).
    (насправді, з Git 2,23 Q3 2019, це буде git restore, не обов’язково git checkout)

Для порівняння, оскільки svn не має індексу, лише робоче дерево svn checkoutбуде скопіювати задану редакцію в окремий каталог.
Більш близький еквівалент для git checkout:

  • svn update (якщо ви перебуваєте в одній гілці, що означає ту саму URL-адресу SVN)
  • svn switch (якщо ви скажете, наприклад, ту саму гілку, але з іншої URL-адреси репортажу SVN)

Всі ці три робочі модифікації дерева ( svn checkout, update, switch) є тільки одна команда в мерзотника: git checkout.
Але оскільки git має також поняття індекс (що "область постановки" між репо та робочим деревом), у вас також є git reset.


Thinkeye в коментарях згадує статтю " Скидання демістифікованих ".

Наприклад, якщо у нас є дві гілки, ' master' і ' develop', які вказують на різні комірки, і ми в даний час знаходимося ' develop' (так HEAD вказує на це), і ми біжимо git reset master, ' develop' сам тепер вкаже на те саме зобов'язання, що ' master'робить.

З іншого боку, якщо ми замість цього побіжимо git checkout master, ' develop' не рухатиметься, HEADсам буде. HEADтепер вкаже на " master".

Отже, в обох випадках ми рухаємося HEADдо пункту вчинення A, але як ми це робимо, дуже відрізняється. resetбуде переміщувати точки відгалуження HEADдо, замовлення переміщається HEAD, щоб вказувати на іншу гілку.

http://git-scm.com/images/reset/reset-checkout.png

Однак щодо цих питань:

LarsH додає в коментарях :

Перший абзац цієї відповіді, однак, вводить в оману: " git checkout... буде оновлено HEAD лише у тому випадку, якщо ви зареєструєте гілку (якщо ні, то в кінцевому підсумку вийде з відокремленою головою)".
Неправда: git checkoutоновить HEAD, навіть якщо ви зареєструєте комісію, яка не є гілкою (і так, ви отримаєте відокремлену HEAD, але вона все одно оновлюється).

git checkout a839e8f updates HEAD to point to commit a839e8f.

Де Ново погоджується в коментарях :

@LarsH правильний.
Друга куля має помилкове уявлення про те, в чому знаходиться HEAD, оновить HEAD лише у тому випадку, якщо ви зареєструєте відділення.
ГОЛОВА йде куди б ви не були, як тінь.
Перевірка деякого невіддільного рефлексу (наприклад, тега) або прямого комітету перемістить HEAD. Окремо голова не означає , що ви відокремлені від голови, це означає , що голівка від'єднується від філії реф, який ви можете побачити, наприклад, з git log --pretty=format:"%d" -1.

  • Приєднані глави держави почнуться з (HEAD ->,
  • від'єднаний все одно покаже (HEAD, але не матиме стрілки до відгалуження.

7
Я б сказав, що git resetйдеться про зміну "label" гілки та необов'язково оновлення індексу або робочого дерева як побічного ефекту. git checkoutйдеться про оновлення робочого дерева та перемикання поточно вибраної гілки (the HEAD).
Мікко Ранталайнен

2
@MikkoRantalainen nope. git resetстановить 100% про HEAD. Він працює навіть у відокремленому режимі HEAD ( stackoverflow.com/a/3965714/6309 ), тобто там, де немає гілки (!). git checkout також працює у відірваному режимі HEAD, або його можна використовувати для перевірки SHA1 в режимі окремої HEAD: знову ж таки жодна гілка не бере участь у цьому випадку.
VonC

3
Подальше читання для всіх загублених душ, надісланих сюди пошуковою системою, я думаю, це того варте: git-scm.com/blog/2011/07/11/reset.html
Thinkeye

2
@Thinkeye хороша довідка. Я включив його разом із відповідним витягом у відповідь для більшої наочності.
VonC

2
Пояснення від Reset Demystified є відмінним. Перший абзац цієї відповіді, однак, вводить в оману: "git checkout ... оновить HEAD лише у тому випадку, якщо ви зареєструєте відділення (якщо ні, то в кінцевому підсумку вийдете з відокремленою HEAD)". Неправда ... git checkout оновить HEAD, навіть якщо ви зареєструєте комісію, яка не є гілкою (і так, ви закінчите з відокремленою HEAD, але вона все одно оновлюється). Можливо, я нерозумію, що ви маєте на увазі під "оновленням"? git checkout a839e8fоновлює HEAD, щоб вказати на вчинення a839e8f.
LarsH

67

У їх найпростішому вигляді resetскидає індекс, не торкаючись робочого дерева, при цьомуcheckout змінює робоче дерево, не торкаючись індексу.

Скидає індекс у відповідність HEAD , робоче дерево залишилося в спокої:

git reset

Концептуально це перевіряє індекс у робоче дерево. Щоб змусити його насправді зробити все, що вам доведеться використати, -fщоб змусити його замінити будь-які локальні зміни. Це безпека, щоб переконатися, що форма "без аргументів" не є руйнівною:

git checkout

Після того, як ви почнете додавати параметри, це правда, що є певне перекриття.

checkoutзазвичай використовується з гілкою, тегом чи фіксацією. У цьому випадку він буде скинутий HEADта індекс до даного комітету, а також виконати зарахування індексу в робоче дерево.

Крім того, якщо ви постачаєте --hard до resetви можете запитатиreset , щоб перезаписати робоче дерево, а також скидання індексу.

Якщо у вас є філія, яку ви перевірили, існує різниця між resetі checkoutколи ви надаєте альтернативну філію чи здійснюєте зобов’язання. resetзмінить поточну гілку на вказівку на обрану комісію, тоді як checkoutзалишить поточну гілку в спокої, але перевірить надану гілку або скористається замість неї.

Інші форми resetтаcommit включають шляхи постачання.

Якщо ви постачаєте шляхи, resetви не можете поставити, --hardі resetбуде змінено лише індексну версію доданих шляхів до версії в наданій комісії (абоHEAD якщо ви не вказали комісію).

Якщо ви надаєте шляхи до checkout, як-от, resetвін оновить версію індексу наданих шляхів, щоб вона відповідала поставленій комісії (або HEAD), але вона завжди перевіряє версію індексу наданих шляхів у робоче дерево.


2
Неправда сказати, що "касинг" не змінює індекс: він змінює його, коли використовується для переходу з гілки в іншу.
wiki1000

У їх найпростішому вигляді скидання скидає індекс, не торкаючись робочого дерева, тоді як замовлення змінює робоче дерево, не торкаючись індексу. : Наскільки це заплутано: |
Гупта

41

Один простий випадок використання при поверненні змін:
1. Використовуйте скидання, якщо ви хочете скасувати постановку зміненого файлу.
2. Використовуйте замовлення, якщо ви хочете відмовитись від змін у нефіксованих файлах.


1
Ідеальна відповідь. Дякую.
користувач358591

11

Ключовою відмінністю в двох словах є те, що reset переміщує поточну посилання на гілку , в той час якcheckout не (вона рухає HEAD).

Як пояснюється в книзі Pro Git у розділі Reset Demystified ,

Перше, що resetпотрібно зробити - це перемістити те, на що вказує HEAD . Це не те саме, що зміна самої HEAD (що і checkoutробить); reset переміщує гілку, на яку вказує HEAD. Це означає, що якщо HEAD встановлено на masterгілку (тобто ви зараз перебуваєте на masterгілці), запуск git reset 9e5e6a4почнеться з masterвказівки на 9e5e6a4 . [наголос додано]

Дивіться також відповідь VonC за а дуже корисний уривок тексту та діаграми з тієї ж статті, яку я не буду дублювати тут.

Звичайно, є набагато більше деталей про те, які ефекти checkoutта resetможуть мати вплив на індекс та робоче дерево, залежно від того, які параметри використовуються. Між двома командами може бути багато подібності та відмінностей. Але, як я бачу, найважливіша різниця полягає в тому, чи переміщують вони кінчик поточної гілки.


2
Хороший відгук, окрім моєї старшої відповіді. +1
VonC

2

Дві команди (скидання та перевірка) абсолютно різні.

checkout X НЕ reset --hard X

Якщо X - назва гілки, checkout Xзмінить поточну гілку, поки reset --hard Xне буде.


2
Але якщо X - це файл чи папка, то вони однакові.
Тед Бігхем,

1

коротка мнемоніка:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.