Есть ли разница между "git reset --hard hash" и "git checkout hash"? - PullRequest
43 голосов
/ 30 марта 2010

Хотя reset и checkout чаще всего используются по-разному, я не вижу, какая разница между этими двумя.

Вероятно, есть кто-то, или никто бы не потрудился добавить опцию --hard, чтобы сделать то, что может сделать базовый checkout.

Может, есть разница в том, как ты увидишь историю?

Ответы [ 3 ]

55 голосов
/ 30 марта 2010

Этот ответ в основном цитируется из моего ответа на предыдущий вопрос: git reset на простом английском .

Два очень разные. Они приводят к одному и тому же состоянию для вашего индекса и рабочего дерева, но итоговая история и текущая ветвь не совпадают.

Предположим, что ваша история выглядит следующим образом, с основной веткой в ​​данный момент проверено:

- A - B - C (HEAD, master)

и вы запускаете git reset --hard B. Вы получите это:

- A - B (HEAD, master)      # - C is still here, but there's no
                            # branch pointing to it anymore

Вы бы действительно получили этот эффект, если бы тоже использовали --mixed или --soft - единственная разница в том, что происходит с вашим рабочим деревом и индексом. В случае --hard рабочее дерево и индекс совпадают B.

Теперь предположим, что вместо этого вы запустите git checkout B. Вы получите это:

- A - B (HEAD) - C (master)

Вы оказались в отключенном состоянии HEAD. HEAD, рабочее дерево, все индексы совпадают B, так же, как и при аппаратном сбросе, но основная ветвь осталась на C. Если вы сделаете новый коммит D в этот момент, вы получите это, что, вероятно, не то, что вы хотите:

- A - B - C (master)
       \
        D (HEAD)

Итак, вы используете checkout для проверки этого коммита. Вы можете возиться с этим, делать то, что вам нравится, но вы оставили свою ветвь позади. Если вы хотите, чтобы ветку тоже переместили, используйте сброс.

14 голосов
/ 30 марта 2010

Если документация, поставляемая с Git, вам не помогает, взгляните на Справочник по визуальному Git от Mark Lodato.

В частности, если вы сравниваете git checkout <non-branch> с git reset --hard <non-branch> (с горячей ссылкой):

мастер проверки git ~ 3 http://marklodato.github.com/visual-git-guide/checkout-detached.svg.png

git reset --hard master ~ 3 http://marklodato.github.com/visual-git-guide/reset-commit.svg.png

Обратите внимание, что в случае git reset --hard master~3 вы оставляете за собой часть DAG ревизий - ни одна ветка не ссылается на некоторые коммиты. Они защищены (по умолчанию) на 30 дней с помощью reflog ; в конечном итоге они будут обрезаны (удалены).

6 голосов
/ 30 марта 2010

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, то есть ГЛАВА указывает на тему 2.

HEAD -> topic2

Затем git reset X сбросит имя 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]
...