Есть ли разница между "git reset --hard hash"? и "git checkout hash"?

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

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

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

вопрос задан 29.03.2010
e-satis
342132 репутация

3 ответов


  • 53 рейтинг

    Этот ответ в основном цитируется из моего ответа на предыдущий вопрос: 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 для проверки этого коммита. Вы можете возиться с этим, делать то, что вам нравится, но вы оставили свою ветвь позади. Если вы хотите, чтобы ветка тоже была перемещена, используйте сброс.

    ответ дан Cascabel, с репутацией 317837, 29.03.2010
  • 14 рейтинг

    Если документация, поставляемая с Git, вам не помогает, посмотрите A Visual Git Reference от Mark Lodato.

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

    git checkout master ~ 3 http: // marklodato. GitHub. ком / зрительно-ГИТ-гид / выписка отдельностоящий. SVG. png

    git reset --hard master ~ 3 http: // marklodato. GitHub. ком / зрительно-ГИТ-гид / сброс фиксации. SVG. png

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

    ответ дан Jakub Narębski, с репутацией 203690, 30.03.2010
  • 6 рейтинг

    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]
    
    ответ дан hasen, с репутацией 79797, 30.03.2010