Qual é a diferença entre "git reset" e "git checkout"?


440

Eu sempre pensei git resete git checkoutcomo o mesmo, no sentido de que ambos trazem o projeto de volta para um commit específico. No entanto, acho que eles não podem ser exatamente iguais, pois isso seria redundante. Qual é a diferença real entre os dois? Estou um pouco confuso, pois o svn só precisa svn coreverter o commit.

ADICIONADO

VonC e Charles explicaram as diferenças entre git resete git checkoutmuito bem. Meu entendimento atual é que git resetreverte todas as alterações de volta para um commit específico, enquanto que git checkoutmais ou menos se prepara para um branch. Achei os dois diagramas a seguir bastante úteis para chegar a esse entendimento:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

ADICIONADOS 3

Em http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html , a finalização da compra e a redefinição podem emular a rebase.

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui



Re: "É errado ou excessivamente simplificado?" Sim, esse primeiro diagrama é enganoso em relação à diferença entre checkout e redefinição. (Pode ser bom em relação às -- filesvariantes; não tenho certeza.) Esse diagrama faz parecer que a principal diferença é se elas afetam o índice ou o WD. Veja minha resposta sobre isso. Os diagramas 2 e 3 são muito úteis para ver a diferença real. Os diagramas 4 e 5 são úteis para verificar se você entende o que esses comandos fazem, mas realmente não o ajudam a chegar lá.
precisa saber é

Encontrei a seção "Confira" no "Git Tools Reset Demystified" para dar o resumo mais útil.
21719 Josiah Yoder

1
prosseek: Se você concorda com o @LarsH que o primeiro diagrama é enganoso, pode removê-lo, por favor?
21719 Josiah Yoder

Observe que o check-out e a redefinição apenas emulam a 2ª parte do rebase e think-like-a-git.netsão necessárias etapas adicionais (fornecidas no artigo vinculado ) para evitar a perda de dados.
cowlinator

Respostas:


198
  • git reseté especificamente sobre a atualização do índice , movendo o HEAD.
  • git checkouté sobre atualizar a árvore de trabalho (para o índice ou a árvore especificada). Ele atualizará o HEAD apenas se você efetuar o checkout de uma ramificação (caso contrário, você terminará com um HEAD desanexado ).
    (na verdade, com o Git 2.23 Q3 2019, isso será git restore, não necessariamente git checkout)

Por comparação, como o svn não tem índice, apenas uma árvore de trabalho svn checkoutcopiará uma determinada revisão em um diretório separado.
O equivalente mais próximo para git checkout:

  • svn update (se você estiver no mesmo ramo, o mesmo URL SVN)
  • svn switch (se você fizer o checkout, por exemplo, da mesma ramificação, mas de outro URL de repo SVN)

Todas essas três modificações árvore de trabalho ( svn checkout, update, switch) tem apenas um comando no git: git checkout.
Mas como o git também tem a noção de índice (essa "área de preparação" entre o repositório e a árvore de trabalho), você também tem git reset.


Thinkeye menciona nos comentários o artigo " Redefinir Desmistificado ".

Por exemplo, se tivermos dois ramos, ' master' e ' develop' apontando para confirmações diferentes, e estamos no momento ' develop' (então HEAD aponta para ela) e executarmos git reset master' develop', agora ela mesma apontará para a mesma confirmação que ' master' faz.

Por outro lado, se corrermos git checkout master, ' develop' não se moverá, HEADele próprio se moverá . HEADagora apontará para ' master'.

Portanto, nos dois casos, estamos nos movendo HEADpara apontar para o commit A, mas como fazemos isso é muito diferente. resetmoverá os HEADpontos da ramificação para, o checkout se moverá HEADpara apontar para outra ramificação.

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

Nesses pontos, porém:

LarsH acrescenta nos comentários :

O primeiro parágrafo desta resposta, no entanto, é enganador: " git checkout... atualizará o HEAD somente se você fizer check-out de uma ramificação (caso contrário, você terminará com um HEAD desanexado)".
Não é verdade: git checkoutatualizará o HEAD mesmo que você faça o check-out de um commit que não seja um branch (e sim, você acaba com um HEAD desanexado, mas ele ainda foi atualizado).

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo concorda nos comentários :

@LarsH está correto.
O segundo marcador tem um equívoco sobre o que o HEAD está atualizando o HEAD somente se você efetuar o checkout de uma ramificação.
A CABEÇA vai para onde você estiver, como uma sombra.
Verificar algumas referências que não sejam de ramificação (por exemplo, uma tag) ou uma confirmação direta, moverá HEAD. Cabeça desanexada não significa que você se desconectou da HEAD, significa que a cabeça está desconectada de uma referência de ramificação, a qual você pode ver, por exemplo git log --pretty=format:"%d" -1,.

  • Os estados principais anexados começarão com (HEAD ->,
  • desanexado ainda será exibido (HEAD, mas não terá uma seta para uma referência de ramificação.

7
Eu diria que git reseté sobre modificar o "rótulo" do ramo e, opcionalmente, atualizar o índice ou a árvore de trabalho como efeito colateral. git checkouttrata da atualização da árvore de trabalho e da alternância da ramificação "selecionada" atualmente (o HEAD).
Mikko Rantalainen

2
@MikkoRantalainen nope. git reseté 100% sobre o HEAD. Ele funciona mesmo no modo HEAD desanexado ( stackoverflow.com/a/3965714/6309 ), o que significa que não ramificação (!). O git checkout também funciona em um modo HEAD desanexado ou pode ser usado para fazer checkout de um SHA1 em um modo HEAD desanexado: novamente, nenhuma ramificação envolvida nesse caso.
VonC

3
Outras leituras para todas as almas perdidas enviado aqui por um motor de busca, eu acho que vale a pena do que: git-scm.com/blog/2011/07/11/reset.html
Thinkeye

2
@ Thinkeye boa referência. Incluí-o, juntamente com um extrato relevante, na resposta para obter mais visibilidade.
VonC

2
A explicação de Reset Demystified é excelente. O primeiro parágrafo desta resposta, no entanto, é enganador: "o git checkout ... atualizará o HEAD somente se você efetuar o checkout de uma ramificação (caso contrário, você terminará com um HEAD desanexado)". Não é verdade ... o git checkout atualizará o HEAD mesmo que você faça o checkout de um commit que não seja um branch (e sim, você acaba com um HEAD desanexado, mas ele ainda foi atualizado). Talvez eu esteja entendendo mal o que você quer dizer com "atualização"? git checkout a839e8fatualiza HEAD para apontar para confirmar a839e8f.
LarsH

67

Na sua forma mais simples, resetredefine o índice sem tocar na árvore de trabalho, enquanto checkoutaltera a árvore de trabalho sem tocar no índice.

Redefine o índice para corresponder HEAD, árvore de trabalho deixada em paz:

git reset

Conceitualmente, isso faz check-out do índice na árvore de trabalho. Para fazê-lo realmente fazer qualquer coisa que você precisaria usar -fpara forçá-lo a substituir as alterações locais. Este é um recurso de segurança para garantir que o formulário "sem argumento" não seja destrutivo:

git checkout

Depois de começar a adicionar parâmetros, é verdade que há alguma sobreposição.

checkoutgeralmente é usado com uma ramificação, etiqueta ou confirmação. Nesse caso, ele será redefinido HEADe o índice para o commit fornecido, além de executar a verificação do índice na árvore de trabalho.

Além disso, se você fornecer --hardpara resetvocê pode pedir resetpara substituir a árvore de trabalho, bem como a redefinição do índice.

Se você atualizou uma ramificação, existe uma diferença crucial entre resete checkoutquando você fornece uma ramificação ou confirmação alternativa. resetalterará a ramificação atual para apontar para a confirmação selecionada enquanto checkoutdeixará a ramificação atual em paz, mas fará o checkout da ramificação fornecida ou confirmará.

Outras formas resete commitenvolvem caminhos de fornecimento.

Se você fornecer caminhos para resetvocê, não poderá fornecer --harde resetalterará apenas a versão de índice dos caminhos fornecidos para a versão no commit fornecido (ou HEADse você não especificar um commit).

Se você fornecer caminhos para checkout, como resetele atualizará a versão de índice dos caminhos fornecidos para corresponder à confirmação fornecida (ou HEAD), mas sempre fará o checkout da versão de índice dos caminhos fornecidos na árvore de trabalho.


2
Não é verdade dizer que "checkout" não altera o índice: ele é alterado quando costumava ir de uma ramificação para outra.
wiki1000

Na sua forma mais simples, redefinir redefine o índice sem tocar na árvore de trabalho, enquanto a verificação geral altera a árvore de trabalho sem tocar no índice. : Quão confuso é isso: |
Aditya Gupta

41

Um caso de uso simples ao reverter a alteração:
1. Use reset se desejar desfazer a preparação de um arquivo modificado.
2. Use o checkout se desejar descartar as alterações nos arquivos não estágios.


1
Resposta perfeita. Obrigado.
user358591

11

A principal diferença em poucas palavras é que reset move a referência de ramificação atual , enquanto checkoutnão move (move HEAD).

Como o livro do Pro Git explica em Redefinir desmistificado ,

A primeira coisa reseta fazer é mover o que HEAD aponta . Isso não é o mesmo que mudar o próprio HEAD (que é o que checkoutfaz); reset move o ramo que o HEAD está apontando. Isso significa que se HEAD estiver definido como masterramo (ou seja, você está atualmente no masterramo), a execução git reset 9e5e6a4começará masterapontando para 9e5e6a4. [enfase adicionada]

Veja também a resposta de VonC para um trecho de texto e diagrama muito útil do mesmo artigo, que não vou duplicar aqui.

É claro que há muito mais detalhes sobre o que efeitos checkoute resetpode ter sobre o índice ea árvore de trabalho, dependendo de quais parâmetros são usados. Pode haver muitas semelhanças e diferenças entre os dois comandos. Mas, a meu ver, a diferença mais crucial é se eles movem a ponta do ramo atual.


2
Bom feedback, além da minha resposta mais antiga. +1
VonC

2

Os dois comandos (reset e checkout) são completamente diferentes.

checkout X NÃO É reset --hard X

Se X for um nome de filial, checkout Xalterará a filial atual, enquanto reset --hard Xnão será.


2
Mas se X é um arquivo ou pasta, eles são os mesmos.
Ted Bigham

1

breves mnemônicos:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.