Есть ли разница между "git reset - hard hash" и "git хеш-чек"?
В то время как reset
и checkout
имеют разные способы использования большую часть времени, я не вижу, какая разница между этими двумя.
Вероятно, один или никто бы не захотел добавить параметр --hard
, чтобы сделать то, что может сделать базовый checkout
.
Может быть, есть разница в том, как вы увидите историю?
Ответы
Ответ 1
Этот ответ в основном цитируется из моего ответа на предыдущий вопрос: git reset на английском языке.
Оба они очень разные. Они приводят к тому же состоянию для вашего индекса и дерева работ, но результирующая история и текущая ветка не совпадают.
Предположим, что ваша история выглядит так: с проверенной ведущей веткой:
- A - B - C (HEAD, master)
и вы запустите git reset --hard B
. Вы получите следующее:
- A - B (HEAD, master) # - C is still here, but there no
# branch pointing to it anymore
Фактически вы получите такой эффект, если используете также --mixed
или --soft
- единственная разница в том, что происходит с вашим деревом и индексом. В случае --hard
дерево работы и индекс соответствуют B
.
Теперь предположим, что вы запустили git checkout B
. Вы получите следующее:
- A - B (HEAD) - C (master)
Вы попали в отдельное состояние HEAD. HEAD
, дерево работы, индексное совпадение B
, то же, что и с жестким reset, но главная ветвь осталась в C
. Если вы сделаете новую фиксацию D
в этот момент, вы получите это, что, вероятно, не то, что вы хотите:
- A - B - C (master)
\
D (HEAD)
Итак, вы используете checkout, чтобы проверить его. Вы можете играть с ним, делать то, что вам нравится, но вы оставили свой филиал позади. Если вы хотите, чтобы ветвь перемещалась, вы используете reset.
Ответ 2
Если документация, поставляемая с Git, вам не помогает, взгляните на A Visual Git Reference Марка Лодато.
В частности, если вы сравниваете git checkout <non-branch>
с git reset --hard <non-branch>
(hotlinked):
(источник: github.com)
![git reset --hard master~3]()
Обратите внимание, что в случае git reset --hard master~3
вы оставляете за собой часть DAG ревизий - на некоторые коммиты не ссылается ни одна ветвь. Они защищены (по умолчанию) 30 дней с помощью reflog; в конечном итоге они будут обрезаны (удалены).
Ответ 3
git-reset hash
устанавливает ссылку ветвления на заданный хеш и, при необходимости, проверяет ее с помощью --hard
.
git-checkout hash
устанавливает рабочее дерево в заданный хэш; и если хеш не является именем ветки, вы получите отдельную голову.
в конечном счете, git имеет дело с 3 вещами:
working tree (your code)
-------------------------------------------------------------------------
index/staging-area
-------------------------------------------------------------------------
repository (bunch of commits, trees, branch names, etc)
git-checkout
по умолчанию просто обновляет индекс и рабочее дерево и может опционально обновлять что-то в репозитории (с опцией -b
)
git-reset
по умолчанию просто обновляет репозиторий и индекс, а также, возможно, рабочее дерево (с опцией --hard
)
Вы можете думать о репозитории следующим образом:
HEAD -> master
refs:
master -> sha_of_commit_X
dev -> sha_of_commit_Y
objects: (addressed by sha1)
sha_of_commit_X, sha_of_commit_Y, sha_of_commit_Z, sha_of_commit_A ....
git-reset
обрабатывает то, на что указывает ссылка на ветку.
Предположим, что ваша история выглядит так:
T--S--R--Q [master][dev]
/
A--B--C--D--E--F--G [topic1]
\
Z--Y--X--W [topic2][topic3]
Имейте в виду, что ветки - это просто имена, которые автоматически совершаются при совершении.
Итак, у вас есть следующие ветки:
master -> Q
dev -> Q
topic1 -> G
topic2 -> W
topic3 -> W
И ваша текущая ветвь topic2
, то есть HEAD указывает на topic2.
HEAD -> topic2
Тогда git reset X
будет reset имя topic2
, чтобы указать на X; это означает, что если вы сделаете фиксацию P в разделе topic2, все будет выглядеть так:
T--S--R--Q [master][dev]
/
A--B--C--D--E--F--G [topic1]
\
Z--Y--X--W [topic3]
\
P [topic2]