В чем разница между "git reset" и "git checkout"?

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

ADDED

Следующая диаграмма объясняет разницу, хотя возможно в упрощенном или неправильном виде. Как вы думаете? Это неправильно или чрезмерно упрощено?

http://a.imageshack.us/img192/5440/screenshot20100903at416.png

ДОБАВЛЕНО 2

VonC и Чарльз объяснили разницу между git reset а также git checkout Очень хорошо. Мое текущее понимание таково, что git reset возвращает все изменения обратно к конкретному коммиту, тогда как git checkout более или менее готовится к ветке. Я нашел следующие две диаграммы весьма полезными для достижения такого понимания:

http://a.imageshack.us/img651/1559/86421927.pnghttp://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 

9 ответов

Решение
  • git reset конкретно об обновлении индекса, перемещая ГОЛОВУ.
  • git checkout об обновлении рабочего дерева (до индекса или указанного дерева). Он обновит ГОЛОВКУ только в том случае, если вы извлекаете ветку (если нет, то в конечном итоге вы получаете отдельный ГОЛОВ).

Для сравнения, поскольку SVN не имеет индекса, только рабочее дерево, svn checkout скопирует данную ревизию в отдельный каталог.
Чем ближе эквивалент для git checkout было бы:

  • svn update (если вы находитесь в той же ветке, то есть тот же URL-адрес SVN)
  • svn switch (если вы извлекаете, например, ту же ветку, но с другого URL репозитория SVN)

Все эти три модификации рабочего дерева (svn checkout, update, switch) есть только одна команда в git: git checkout,
Но так как git также имеет понятие индекса ("промежуточной области" между репо и рабочим деревом), у вас также есть git reset,


Thinkeye упоминает в комментариях статью " Сброс демистификации ".

Например, если у нас есть две ветви, master ' а также ' develop 'указывает на разные коммиты, и мы в настоящее время на develop '(так ГОЛОВА указывает на это), и мы бежим 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... будет обновлять ГОЛОВКУ только в том случае, если вы извлекаете ветку (если нет, то в итоге вы получаете отдельный ГОЛОВ) ".
Не правда: git checkout обновит HEAD, даже если вы извлекаете коммит, который не является ветвью (и да, в конечном итоге вы получаете отдельный HEAD, но он все еще обновляется).

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo соглашается в комментариях:

@LarsH правильно.
Второй пункт имеет неправильное представление о том, что в HEAD будет обновлять HEAD, только если вы извлекаете ветку.
ГОЛОВА идет везде, где ты, как тень.
Извлечение ссылки, не относящейся к ветке (например, тега) или фиксации напрямую, переместит HEAD. Отделенная головка не означает, что вы отсоединились от ГОЛОВКИ, это означает, что головка отделена от ссылки на ветку, из которой вы можете видеть, например, git log --pretty=format:"%d" -1,

  • Присоединенные состояния головы начнутся с (HEAD ->,
  • оторваться все равно покажет (HEAD, но не будет стрелка на ветке ref.

В простейшей форме 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), но он всегда извлекает индексную версию предоставленных путей в рабочее дерево.

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

Ключевое отличие в двух словах в том, что reset перемещает текущую ссылку ветви, в то время как checkout не (движется ГОЛОВА).

Как объясняет книга Pro Git в разделе " Сбросить демистификацию",

Во-первых reset будет делать то, на что указывает HEAD. Это не то же самое, что изменение самой HEAD (вот что checkout делает); reset перемещает ветку, на которую указывает HEAD. Это означает, что для HEAD установлено значение master филиал (т.е. вы в настоящее время на master филиал), работает git reset 9e5e6a4 начнем с создания master указать на 9e5e6a4, [выделение добавлено]

См. Также ответ VonC для очень полезного отрывка текста и диаграммы из той же статьи, который я не буду здесь дублировать.

Конечно, есть гораздо больше деталей о том, какие эффекты checkout а также reset может иметь индекс и рабочее дерево, в зависимости от того, какие параметры используются. Там может быть много сходств и различий между двумя командами. Но, как я понимаю, самое важное различие заключается в том, перемещают ли они кончик текущей ветви.

Atlassian дает нам отличное объяснение сбросаgit, проверки git и так далее, git revert. В этой статье объясняется различное использование этих команд на разных уровнях - файл, промежуточный снимок и фиксация.

https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting

Краткая мнемоника:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD

Две команды (сброс и проверка) совершенно разные.

checkout X НЕ ЯВЛЯЕТСЯ reset --hard X

Если X является именем ветви, checkout X изменит текущую ветку, пока reset --hard X не буду.

git reset-> удаляет все файлы из подготовленной области , т.е. отменяет действиеgit add <files>

git reset <commit_ID>-> отменяет коммиты и промежуточную обработку всех файлов после указанного коммита.

если добавлено--hardс помощью команды сброса, затем он удаляет файлы из подготовленной области , а также из вашего каталога.

git checkout <commit_ID>-> вы вернулись в указанное состояние фиксации, но вы не находитесь ни в одной ветке.

если ты напечатаешьgit branch -a, вы увидите, что находитесь в

(HEAD отключен в <commit_ID>)

.

согласно консоли:

Вы находитесь в состоянии «отсоединенный HEAD». Вы можете осмотреться, внести экспериментальные изменения и зафиксировать их, а также отменить любые фиксации, сделанные в этом состоянии, не затрагивая ни одну ветку, переключившись обратно на ветку.

и вам будет предложено два варианта:

  1. git switch -c <new-branch-name>: на основе этого коммита будет создана новая ветка, которая станет вашей текущей веткой.
  2. git switch -c-> по сути это отмена команды оформления заказа, которая возвращает вас в старую ветку.

Вот прояснение двусмысленности:

  • git checkout переместит HEAD в другую фиксацию (также может быть изменено имя ветки), но:
    1. в какой бы ветке вы ни находились, указатель на верхушку этой ветки (например, «main») останется неизменным (так что вы можете оказаться в состоянии отдельной главы ).

    2. Кроме того, промежуточная область и рабочий каталог останутся неизменными (в том же состоянии, в котором они были до оформления заказа).

Примеры:

      git checkout 3ad2bcf <--- checkout to another commit
git checkout another-branch <--- checkout to another commit using a branchname
  • git reset также перемещает HEAD , но опять же, с двумя отличиями:

    1. Он также перемещает указатель, указывающий на фиксацию, в конце текущей ветки. Например, предположим, что указатель на текущую ветку называется «main», затем вы выполняете git-reset, теперь основной указатель будет указывать на другую фиксацию, а HEAD также будет указывать на эту фиксацию (ну, в основном, HEAD указывает на этот коммит косвенно, указывая на основной указатель, это все еще прикрепленная голова (!) , Но здесь это не имеет никакого значения).

    2. Git-reset не обязательно оставляет промежуточную область и рабочий каталог в том же состоянии, в котором они находились до выполнения сброса. Как известно, есть три типа сброса: мягкий, смешанный (по умолчанию) и жесткий:

      • При мягком сбросе промежуточная область и рабочий каталог остаются в том состоянии, в котором они были до сброса (аналогично проверке в этом отношении, но не забывайте разницу № 1).
      • При смешанном сбросе, который является типом сброса по умолчанию, в дополнение к разнице №1, в промежуточной области, предлагаемой следующей фиксации (в основном, что вы добавили git), также будет установлен новый указатель на HEAD совершить. НО в рабочем каталоге все файлы по-прежнему будут содержать ваши последние изменения (поэтому этот тип сброса является сбросом по умолчанию, чтобы вы не потеряли свою работу).
      • При аппаратном сбросе, в дополнение к разнице № 1, все три дерева HEAD, staging-area и ТАКЖЕ рабочий каталог изменятся на новую фиксацию с указанием на HEAD.

Примеры:

      git reset --soft 3ad2bcf
git reset da3b47
Другие вопросы по тегам