Isso soa familiar? “Socorro! Eu me comprometi com o ramo errado! ” “Aconteceu de novo … Onde está meu commit?”

Bem, eu estive lá tantas vezes. Alguém chama meu nome pedindo ajuda quando algo dá errado com git. E isso aconteceu não apenas quando eu estava ensinando alunos, mas também enquanto trabalhava com desenvolvedores experientes.

Com o tempo, eu meio que me tornei “o cara do Git”.

Nós usamos git o tempo todo e geralmente nos ajuda a fazer o trabalho. Mas às vezes, e com muito mais frequência do que gostaríamos, as coisas dão errado.

Talvez tenhamos nos comprometido com o ramo errado. Talvez tenhamos perdido algum código que escrevemos. Talvez tenhamos cometido algo que não pretendíamos.

Fonte: xkcd.com

Existem muitos recursos online sobre git, e alguns deles (como este) realmente se concentram no que acontece nesses cenários indesejados.

Mas sempre achei que faltavam esses recursos “porque” . Quando fornecido com um conjunto de comandos, o que cada comando faz? E como você chegou a esses comandos em primeiro lugar? 🤔

Dentro em um post anterior, forneci uma introdução visual aos componentes internos do Git. Apesar de compreender os aspectos internos de git é útil, obter a teoria quase nunca é suficiente. Como aplicamos nosso conhecimento de gitinternos e usá-lo para corrigir problemas em que nos metemos?

Neste post, gostaria de preencher essa lacuna e elaborar sobre o git reset comando. Vamos entender o que git reset faz nos bastidores e, em seguida, aplica esse conhecimento para resolver vários cenários. 😎

Fundamentos comuns – diretório de trabalho, índice e repositório

A fim de compreender os mecanismos internos de git reset, é importante entender o processo de registro de mudanças dentro git . Especificamente, quero dizer o diretor de trabalho, a índice, e a repositório.

Se você tiver certeza sobre esses termos, sinta-se à vontade para pular para a próxima seção. Se você quiser uma explicação ainda mais profunda, veja isto postagem anterior.

Quando trabalhamos em nosso código-fonte, trabalhamos a partir de um trabalho dir – qualquer diretório em nosso sistema de arquivos que tenha um repositórioassociado a isso. Ele contém as pastas e arquivos do nosso projeto, e também um diretório chamado .git.

Depois de fazer algumas alterações, queremos gravá-las em nosso repositório . UMA repositório (repopara encurtar) é uma coleção de compromete , cada um dos quais é um arquivo do que o projeto árvore de trabalho parecia em uma data passada, seja em nossa máquina ou de outra pessoa.

1 2

Vamos criar um arquivo no diretório de trabalho e executar git status:

2 4

Ainda, gitnão confirma as alterações do árvore de trabalhodiretamente no repositório.

Em vez disso, as alterações são registradas primeiro em algo chamado de índice, ou o área de preparação. Ambos os termos se referem à mesma coisa e são usados ​​com frequência em git documentação de. Usaremos esses termos de forma intercambiável ao longo deste post.

Quando usamos git add, adicionamos arquivos (ou alterações dentro de arquivos) ao área de preparação . Vamos usar este comando no arquivo que criamos anteriormente:

3 2

Como git status revela, nosso arquivo é encenado(e pronto “para ser comprometido”). No entanto, não faz parte de nenhum comprometer. Em outras palavras, agora está no diretor de trabalho, assim como o índice, mas não no repositório .

6 3

Em seguida, quando usamos git commit, nós criamos um comprometercom base no estado do índice . Então o novo comprometer (commit 3 no exemplo abaixo) incluirá o arquivo adicionado ao índice de antemão.

7 2

Em outras palavras, o diretor de trabalho tem exatamente o mesmo estado que o índicee a repositório .

O comando git commit também faz o ramo atual master aponte para o recém-criado comprometerobjeto.

8 2

O funcionamento interno do git reset

Eu gosto de pensar em git reset como um comando que inverte o processo descrito acima (introduzindo uma mudança no diretor de trabalho, adicionando-o ao índice, e depois comprometerpara o repositório )

O reset do Git tem três modos de operação –--soft, --mixed, ou --hard. Eu os vejo como três estágios:

  • Etapa 1 – atualização HEADgit reset --soft
  • Estágio 2 – atualização índicegit reset --mixed
  • Estágio 3 – atualização diretor de trabalho git reset --hard

Etapa 1 – atualização HEAD (git reset --soft)

Primeiro, git reset atualiza tudo HEAD aponta para. Para git reset --hard HEAD~1 vai mover o que HEAD aponta para (no exemplo acima, master) para HEAD~1. Se o— -softbandeira é usada, git reset pára aí.

Continuando com nosso exemplo acima, HEAD vai apontar para commit 2, e assim new_file.txt não fará parte da árvore do commit atual. Será, no entanto, parte do índice e a diretor de trabalho.

9 2

Olhando para git status, podemos ver que o arquivo é realmente testado, mas não confirmado:

10 2

Em outras palavras, revertemos o processo para o estágio em que usamos git add, mas ainda não usei git commit.

Estágio 2 – atualizar índice para HEAD (git reset --mixed)

Se usarmos git reset --mixed HEAD~1, então git não vai parar depois de atualizar o que quer que seja HEADaponta para ( master )para HEAD~1. Ele também atualizará o índice para (o já atualizado) HEAD .

Em nosso exemplo, isso significa que o índice terá o mesmo estado que comprometer 2 :

11 1

Então, revertemos o processo para o estágio antes de usargit add– o arquivo recém-criado agora faz parte do diretório de trabalho, mas o índice e a repositórionão são.

12 1

Estágio 3 – atualizar o diretório de trabalho para indexar (git reset --hard)

Usando git reset — hard HEAD~1, depois de atualizar tudo HEADaponta para (master )para HEAD~1, bem como atualizar o índice para (o já atualizado) HEAD , git seguirá em frente e atualizará o diretor de trabalho para se parecer com o índice.

Em nosso exemplo, isso significa que o diretor de trabalho terá o mesmo estado que o índice,que já tem o mesmo estado que comprometer 2:

13 1

Na verdade, revertemos todo o processo para antes mesmo de criar my_file.txt.

Aplicando nosso conhecimento a cenários do mundo real

Agora que entendemos como git reset funciona, vamos aplicar esse conhecimento para salvar o nosso dia! 💪

1. OOPS! Eu cometi algo por engano.

Vamos considerar o seguinte cenário. Criamos um arquivo com a string This is very importnt, encenou e cometeu.

14 1

E então … Ops! Percebemos que ocorreu um erro de digitação. 🙈

Bem, agora sabemos que podemos resolver isso facilmente. Podemos reverter nosso último commit e obter o arquivo de volta para o diretório de trabalho usando git reset --mixed HEAD~1. Agora, podemos editar o conteúdo do nosso arquivo, prepará-lo e confirmá-lo novamente.

Dica:neste caso específico, também podemos usar git commit --amend, conforme descrito aqui.

2. OOPS! Eu comprometi algo no branch errado – e preciso disso em um novo branch

Todos nós já passamos por isso. Fizemos um pouco de trabalho e depois o comprometemos …

15 1

Oh não, nós nos comprometemos com master branch, embora devêssemos ter criado um novo branch e emitido uma solicitação pull. 🙈

Neste estágio, acho útil visualizar o estado em que estamos e para onde gostaríamos de chegar:

16

Na verdade, existem três mudanças entre o estado atual e o desejado.

Primeiro, new pontos de ramificação para nosso commit adicionado recentemente. Segundo, master aponta para o commit anterior. Terceiro, HEAD aponta para new.

Podemos chegar ao estado desejado por meio de três etapas simples:

Primeiro, faça new ponto de ramificação para o commit adicionado recentemente – isso pode ser feito simplesmente usando git branch new. Portanto, alcançamos o seguinte estado:

17

Em segundo lugar, faça master apontar para o commit anterior (em outras palavras, para HEAD~1) Podemos fazer isso usando git reset --hard HEAD~1. Portanto, alcançamos o seguinte estado:

18

Por último, gostaríamos de estar no ramo new, isto é, façaHEADaponta para new. Isso é facilmente alcançado executando git checkout new.

Contudo:

  • git branch new
  • git reset --hard HEAD~1
  • git checkout new

3. OOPS! Eu comprometi algo no branch errado – e eu preciso disso em outro branch já existente

Nesse caso, seguimos as mesmas etapas do cenário anterior – fizemos algum trabalho e depois o comprometemos …

19

Oh não, nós nos comprometemos com master branch, embora devêssemos ter nos comprometido com outro branch que já existe. 🙈

Vamos voltar à nossa prancheta:

20

Novamente, podemos ver que existem algumas diferenças aqui.

Primeiro, precisamos que o commit mais recente esteja em existing ramo. Desde a master atualmente aponta para ele, podemos simplesmente perguntar gitpara pegar o commit recente de master ramificar e aplicá-lo a existing ramo assim:

  • git checkout existing– Mudando para existing ramo
  • git cherry-pick master– aplicando o último commit em master ramificar para o atual (existing) ramo

Agora, chegamos ao seguinte estado:

21

Agora só precisamos fazer master aponte para o commit anterior, ao invés do último. Para isso podemos:

  • git checkout master– mude a ramificação ativa para master novamente.
  • git reset --hard HEAD~1– agora estamos de volta ao ramo original.

E alcançamos nosso estado desejado:

22

Resumo

Nesta postagem, aprendemos como git reset opera, e esclareceu seus três modos de operação –--soft, --mixed, e --hard.

Em seguida, aplicamos nosso conhecimento sobre git reset para resolver alguns problemas da vida real com git .

Compreendendo o caminho git opera, podemos enfrentar com segurança todos os tipos de cenários e também apreciar a beleza desta ferramenta 😎

Em postagens futuras, abordaremosgitcomandos e como eles podem nos ajudar a resolver todos os tipos de situações indesejadas.

Omer Rosenbaum, NadarDiretor de Tecnologia da. Especialista em treinamento cibernético e fundador da Checkpoint Security Academy. Autor de Redes de Computadores (em hebraico). Me visite Canal do Youtube.

Recursos adicionais



Fonte