Какая разница между "git reset" и "git checkout"?

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

ADDED

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 оформить заказ и сброс можно эмулировать ребаз.

enter image description here

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

enter image description here

Ответ 1

  • 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 " (так HEAD указывает на него), и мы запустим git reset master, теперь будет develop и сам "Develop" указывает на тот же коммит, который делает ' master '.

С другой стороны, если мы вместо этого запустим git checkout master, " develop " не будет, а сама HEAD. HEAD теперь будет указывать на " master ".

Итак, в обоих случаях мы перемещаем HEAD чтобы указать на коммит A, но то, как мы это делаем, сильно отличается. reset переместит точки HEAD ветки, checkout переместит саму HEAD, чтобы указать на другую ветку.

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

По этим пунктам, однако:

LarsH добавляет в комментариях:

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

git checkout a839e8f updates HEAD to point to commit a839e8f.

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

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

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

Ответ 2

В своей простейшей форме reset сбрасывает индекс, не касаясь рабочего дерева, а checkout изменяет рабочее дерево, не касаясь индекса.

Сбрасывает индекс в соответствии с HEAD, дерево обработки остается в покое:

git reset

Концептуально это проверяет индекс в рабочем дереве. Чтобы заставить его фактически сделать что-нибудь, вам придется использовать -f, чтобы заставить его перезаписать любые локальные изменения. Это функция безопасности, чтобы убедиться, что форма "без аргументов" не является разрушительной:

git checkout

Как только вы начинаете добавлять параметры, это правда, что есть некоторое перекрытие.

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

Кроме того, если вы отправите --hard в reset, вы можете попросить reset перезаписать рабочее дерево, а также сбросить индекс.

Если у вас в настоящее время выведена ветка, существует ключевое значение между reset и checkout при поставке альтернативной ветки или фиксации. reset изменит текущую ветвь на точку на выбранном коммита, тогда как checkout оставит только текущую ветку, но будет проверять отправленную ветку или вместо нее.

Другие формы reset и commit включают в себя пути доставки.

Если вы отправляете пути к reset, вы не можете поставить --hard, а reset изменит только индексную версию предоставленных путей на версию в поставляемом коммите (или HEAD, если вы не укажете фиксации).

Если вы отправляете пути к checkout, например reset, он обновляет версию индекса предоставленных путей в соответствии с предоставленным commit (или HEAD), но всегда будет проверять индексную версию указанных путей в рабочего дерева.

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

checkout X НЕ reset --hard X

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