В чем разница между "git reset" и "git checkout"?
Я всегда думал о git reset
а также git checkout
как то же самое, в том смысле, что оба возвращают проект к определенной фиксации. Однако я чувствую, что они не могут быть точно такими же, поскольку это было бы излишним. Какова реальная разница между ними? Я немного запутался, так как SVN имеет только svn co
отменить коммит.
ADDED
Следующая диаграмма объясняет разницу, хотя возможно в упрощенном или неправильном виде. Как вы думаете? Это неправильно или чрезмерно упрощено?
ДОБАВЛЕНО 2
VonC и Чарльз объяснили разницу между git reset
а также git checkout
Очень хорошо. Мое текущее понимание таково, что git reset
возвращает все изменения обратно к конкретному коммиту, тогда как git checkout
более или менее готовится к ветке. Я нашел следующие две диаграммы весьма полезными для достижения такого понимания:
ДОБАВЛЕНО 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
Сам указывать на другую ветку.
По этим пунктам, однако:
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». Вы можете осмотреться, внести экспериментальные изменения и зафиксировать их, а также отменить любые фиксации, сделанные в этом состоянии, не затрагивая ни одну ветку, переключившись обратно на ветку.
и вам будет предложено два варианта:
-
git switch -c <new-branch-name>
: на основе этого коммита будет создана новая ветка, которая станет вашей текущей веткой. -
git switch -c
-> по сути это отмена команды оформления заказа, которая возвращает вас в старую ветку.
Вот прояснение двусмысленности:
- git checkout переместит HEAD в другую фиксацию (также может быть изменено имя ветки), но:
в какой бы ветке вы ни находились, указатель на верхушку этой ветки (например, «main») останется неизменным (так что вы можете оказаться в состоянии отдельной главы ).
Кроме того, промежуточная область и рабочий каталог останутся неизменными (в том же состоянии, в котором они были до оформления заказа).
Примеры:
git checkout 3ad2bcf <--- checkout to another commit
git checkout another-branch <--- checkout to another commit using a branchname
git reset также перемещает HEAD , но опять же, с двумя отличиями:
Он также перемещает указатель, указывающий на фиксацию, в конце текущей ветки. Например, предположим, что указатель на текущую ветку называется «main», затем вы выполняете git-reset, теперь основной указатель будет указывать на другую фиксацию, а HEAD также будет указывать на эту фиксацию (ну, в основном, HEAD указывает на этот коммит косвенно, указывая на основной указатель, это все еще прикрепленная голова (!) , Но здесь это не имеет никакого значения).
Git-reset не обязательно оставляет промежуточную область и рабочий каталог в том же состоянии, в котором они находились до выполнения сброса. Как известно, есть три типа сброса: мягкий, смешанный (по умолчанию) и жесткий:
- При мягком сбросе промежуточная область и рабочий каталог остаются в том состоянии, в котором они были до сброса (аналогично проверке в этом отношении, но не забывайте разницу № 1).
- При смешанном сбросе, который является типом сброса по умолчанию, в дополнение к разнице №1, в промежуточной области, предлагаемой следующей фиксации (в основном, что вы добавили git), также будет установлен новый указатель на HEAD совершить. НО в рабочем каталоге все файлы по-прежнему будут содержать ваши последние изменения (поэтому этот тип сброса является сбросом по умолчанию, чтобы вы не потеряли свою работу).
- При аппаратном сбросе, в дополнение к разнице № 1, все три дерева HEAD, staging-area и ТАКЖЕ рабочий каталог изменятся на новую фиксацию с указанием на HEAD.
Примеры:
git reset --soft 3ad2bcf
git reset da3b47