Skip to content

Instantly share code, notes, and snippets.

@geocarvalho
Created July 1, 2018 22:03
Show Gist options
  • Save geocarvalho/d7dfdf7990fd818ffab62466ffcc6068 to your computer and use it in GitHub Desktop.
Save geocarvalho/d7dfdf7990fd818ffab62466ffcc6068 to your computer and use it in GitHub Desktop.
Learn_git_branching

Introdução aos commits no Git

  • Um commit em um repositório git registra uma fotografia (snapshot) de todos os arquivos no seu diretório. É como um grande copy&paste, mas ainda melhor!
  • O Git tem por objetivo manter os commits tão leves quanto possível, de forma que ele não copia cegamente o diretório completo toda vez que você commita. Ele pode (quando possível) comprimir um commit como um conjunto de mudanças (ou um "delta") entre uma versão do seu repositório e a seguinte.
  • O Git também mantém um histórico de quando ocorreu cada commit. É por isso que a maioria dos commits tem ancestrais acima de si -- que indicamos usando setas na nossa visualização. Manter a história é ótimo para todos que trabalham no projeto!
  • Há muito para aprender, mas por enquanto pense nos commits como snapshots do seu projeto. Os commits são muito leves, e mudar de um para outro é extremamente rápido!
  • Vejamos o que isso significa na prática. Abaixo, temos uma visualização de um (pequeno) repositório git. Há dois commits no momento: o commit inicial, C0, e um commit que se segue, C1, que poderia conter algumas mudanças interessantes. 0.neq1op9d7a
$ git commit

0.x8akn5du3xq

  • Acabamos de fazer mudanças no repositório e as guardamos como um commit. O commit que acabamos de criar tem um pai, C1, que referencia em qual commit ele se baseou.

Ramos no Git

  • Ramos no Git também são incrivelmente leves. Eles são simplesmente referências a um commit específico -- e nada mais. É por isso que muitos entusiastas do Git entoam o mantra:

ramifique cedo, ramifique sempre

  • Devido a não existir sobrecarga de armazenamento / memória associada à criação de ramos, é mais fácil dividir logicamente o seu trabalho do que ter ramos grandes e gordos.

  • Quando começarmos a misturar ramos e commits, vamos ver como esses dois recursos combinam bem. Por enquanto, só lembre que um ramo diz essencialmente "Quero incluir o trabalho deste commit e de todos os seus ancestrais".

  • Vejamos como os ramos funcionam na prática. Aqui vamos criar um novo ramo chamado newImage 0.p3kdmie5gta

$ git branch newImage

0.qfcsuzbye3n

  • Veja, é só isso que você tem que fazer para ramificar! O ramo newImage agora se refere ao commit `
  • Vamos tentar colocar algum trabalho neste novo ramo.
$ git commit

0.d8ou1qwovc8

  • Ah não! O ramo master se moveu mas o newImage não! Isso é porque o novo ramo não era o "ativo", e é por isso que o asterisco (*) estava no master.
  • Vamos contar ao git que queremos fazer checkout no ramo com:
$ git checkout [nome]
  • Isso vai nos situar no ramo antes de commitarmos nossas mudanças. 0.gwjgglbzfki
$ git checkout newImage; git commit

0.uspbtn08vz

  • Aqui vamos nós! Nossas mudanças foram gravadas no novo ramo

Merge no Git

  • Ótimo! Agora sabemos como commitar e criar ramos. Agora precisamos aprender uma forma de combinar o trabalho de dois ramos diferentes. Isso nos permitirá ramificar, desenvolver um novo recurso, e então combiná-lo de volta.

  • O primeiro método para combinar trabalho que vamos examinar é o git merge. O merge do Git cria um commit especial que possui dois pais únicos. Um commit com dois pais essencialmente significa "Quero incluir todo o trabalho deste pai aqui com o daquele outro pai ali, e com o do conjunto de todos os seus ancestrais."

0.5nf2ukcv5n

  • Aqui nós temos dois ramos; cada um tem um commit que é único. Isso significa que nenhum ramo inclui o conjunto do "trabalho" que foi realizado no repositório. Vamos consertar isso com um merge. Vamos juntar o ramo bugFix no master:
$ git merge bugFix

0.84gz632k8r

  • Uau! Viu isso? Antes de tudo, o master agora aponta para um commit que possui dois pais. Se você seguir as setas subindo a árvore de commits a partir do master, você será capaz de encontrar, ao longo do caminho até a raiz, qualquer um dos commits. Isso significa que o master contém todo o trabalho realizado no repositório até o momento.
  • Vamos juntar o master no bugFix:
$ git checkout bugFix; git merge master

0.1g6nh1kz9s4

  • Como o bugFix é um ancestral do master, o git não teve trabalho nenhum; ele só precisou mover o bugFix para o mesmo commit do master. Agora todos os commits possuem a mesma cor, o que significa que ambos os ramos contém todo o trabalho realizado no repositório! Eba!

git checkout -b bugFix; git commit; git checkout master; git commit; git merge bugFix


Introdução ao Rebase

  • A segunda forma de combinar trabalho entre ramos é o rebase. O rebase essencialmente pega um conjunto de commits, "copia" os mesmos, e os despeja em outro lugar. Isso pode parecer confuso, mas a vantagem do rebase é que ele pode ser usado para construir uma sequência mais bonita e linear de commits. O registro de commits (história do repositório) ficará muito mais limpa se for utilizado apenas rebase em vez de merge.

  • Abaixo temos dois ramos novamente; note que o ramo bugFix está atualmente ativo (veja o asterisco) 0.3td4y7tkmj7

  • Queremos mover nosso trabalho do bugFix diretamente dentro do master. Desta forma, vai parecer que esses dois recursos foram desenvolvidos sequencialmente, quando na realidade foram feitos em paralelo. Vamos fazê-lo com o comando git rebase

$ git rebase master

0.0tfjhvohfde

  • Incrível! Agora o trabalho do nosso ramo bugFix está logo após o do master, e temos uma linda sequência linear de commits. Perceba que o commit C3 ainda existe em algum lugar (ele está clareado na árvore), e que o C3' é a "cópia" que rebaseamos no master. O único problema é que o master não foi atualizado também, vamos fazê-lo agora...
  • Agora o ramo master está ativo. Vamos em frente, fazer rebase no bugFix...
$ git rebase bugFix

0.64w14tz9k9k

  • Aí está! Como o master era um ancestral do bugFix, o git simplesmente moveu a referência do ramo master para frente na história.
$ git checkout -b bugFix; git commit; git checkout master; git commit; git checkout bugFix; git rebase master

Solte a sua (HEAD)

  • Primeiro temos que conversar sobre a "cabeça" (HEAD). HEAD é um nome simbólico para o commit atualmente ativo (que sofreu checkout por último). É essencialmente o commit sobre o qual você está trabalhando no momento.
  • O HEAD sempre aponta para o commit mais recentemente copiado sobre a árvore de trabalho (arquivos do projeto). A maioria dos comandos do git que realizam mudanças sobre a árvore de trabalho começarão mudando o HEAD.
  • Normalmente o HEAD aponta para o nome de um ramo (por exemplo, bugFix). Quando você commita, o status do bugFix é alterado e essa mudança ocorre também sobre o HEAD. Vejamos isto em ação. Aqui vamos mostrar o HEAD antes e depois de um commit. 0.52wdzbi2kig
$ git checkout C1; git checkout master; git commit; git checkout C2

0.p7tkeilsubp

  • Veja! O HEAD estava se escondendo ao lado do nosso master esse tempo todo.
  • Soltar o HEAD significa anexá-lo a um commit em vez de anexá-lo a um ramo. Antes do estado solto (detached), é assim como se parece: 0.e088qndw1c4

HEAD -> master -> C1

$ git checkout C1
  • E agora é 0.wj0s26l4nig

HEAD -> C1

$ git checkout C4

Referências relativas

  • Mover-se pela árvore do Git especificando o hash do commit pode se tornar um pouco entediante. No mundo real, você não terá à sua disposição essa bonita visualização da árvore ao lado do seu terminal, então você terá de usar o comando git log para ver os hashes.
  • Além disso, os hashes são geralmente muito maiores no mundo real. Por exemplo, o hash do commit que introduziu o nível de exercícios anterior é fed2da64c0efc5293610bdd892f82a58e8cbc5d8. Não é algo exatamente fácil de lembrar.
  • O que salva é que o Git é inteligente com os hashes. Ele só exige que você especifique a quantidade de caracteres do hash suficiente para identificar unicamente o commit. Então eu posso digitar apenas fed2 em vez da grande string acima.
  • Como eu disse, especificar commits pelo hash não é a sempre o mais conveniente, e é por isso que o Git suporta referências relativas. Elas são fantásticas!
  • Com referências relativas, você pode começar a partir de um ponto fácil de lembrar (como o ramo bugFix ou o HEAD) e referenciar a partir dali.
  • Commits relativos são poderosos, mas vamos introduzir apenas dois tipos simples aqui:
    • Mover para cima um commit por vez com ^;
    • Mover para cima um número de vezes com ~<num>.
  • Vamos dar uma olhada no operador circunflexo (^) primeiro. Cada vez que você adicioná-lo a um nome de referência, você está dizendo ao Git para encontrar o pai do commit especificado. Então, dizer master^ é equivalente a "o primeiro pai do master". master^^ é o avô (ancestral de segunda geração) do master. Vamos fazer checkout do commit logo acima do master: 0.wsvpxehbrk
$ git checkout master^

0.qxbmrd7ym9

  • Boom! Pronto. Muito mais fácil que digitar o hash do commit.
  • Você também pode usar o HEAD como parte de uma referência relativa. Vamos usar isso para nos mover para cima algumas vezes na árvore de commits. 0.yttsbu9xui
$ git checkout C3; git checkout HEAD^; git checkout HEAD^; git checkout HEAD^

0.i72k46hkruo

  • Fácil! Podemos viajar para trás no tempo com HEAD^
$ git checkout bugFix^

Referências relativas #2

  • Digamos que você queira se mover vários níveis para cima na árvore de commits. Pode ser entediante digitar ^ várias vezes, e por isso o Git possui também o operador til (~). Um número pode ser passado (opcionalmente) após o operador til, especificando o número de ancestrais que você deseja subir. Vamos vê-lo em ação:

0.hn40zlzhcvu

$ git checkout HEAD~4

0.ms6gk0ofmbv

  • Boom! Tão conciso. Referências relativas são incríveis.
  • Agora que você é um especialista em referências relativas, vamos usá-las de fato para alguma coisa. Uma das situações mais comuns na qual eu uso referências relativas é quando quero trocar ramos de lugar. Você pode redefinir diretamente o commit para o qual um ramo aponta com a opção -f. Desta forma, o seguinte comando: 0.1ya8dt3adwl
$ git branch -f master HEAD~3

0.xd9zx4nnqug

  • Move (à força) o ramo master 3 ancestrais acima do HEAD.
  • Aqui vamos nós! As referências relativas nos deram uma forma concisa de nos referirmos ao C1, e a movimentação de ramos (com -f) nos deu uma forma de apontar rapidamente um ramo para esse local.
$ git checkout HEAD^; git branch -f master C6; git branch -f bugFix HEAD^

Revertendo mudanças no git

  • Existem várias maneiras de reverter mudanças no Git. E assim como o ato de commitar, reverter mudanças no Git também tem um componente de baixo nível (a preparação, ou staging, de arquivos ou trechos de arquivos individuais) e um componente de alto nível (como as mudanças são, de fato, revertidas). Aqui vamos focar neste último ponto.
  • Há duas maneiras principais de desfazer mudanças no Git -- uma delas é usando git reset, e a outra é usando git revert. Vamos olhar cada uma delas.
    • O comando git reset reverte mudanças movendo para trás no tempo (para um commit mais antigo) a referência do ramo. Desta forma, você pode pensar nessa operação como uma "reescrita do histórico"; o git reset vai mover o ramo para trás como se o commit nunca tivesse existido. Vejamos como funciona: 0.mfyifzzj71
$ git reset HEAD~1

0.5i90drlg43s

  • Legal! O Git simplesmente moveu a referência do ramo master de volta para C1; agora o nosso repositório local está em um estado como se o C2 nunca tivesse acontecido.
  • Embora o reset funcione muito bem em ramos locais no seu próprio computador, o método utilizado de "reescrever o histórico" não funciona com ramos remotos que outras pessoas estejam usando. Para reverter mudanças e conseguir compartilhar essas mudanças com os outros, precisamos usar o git revert. Vejamo-lo em ação
git revert HEAD

0.ltt1ezhgbc

  • Estranho, um novo commit surgiu abaixo do commit que queríamos reverter. Isso é porque o novo commit C2' introduz mudanças -- acontece que as mudanças que ele introduz revertem exatamente aquelas do commit C2.
  • Com o revert, você pode fazer push das suas mudanças para compartilhá-las com os outros.
$ git reset HEAD^; git checkout pushed; git revert HEAD

Introdução ao cherry-pick

  • Por enquanto nós abordamos o básico do Git -- commitar, criar ramos, e mover-se pela árvore. Apenas esses conceitos já são suficientes para utilizar 90% do poder dos repositórios Git, e cobrem as principais necessidades dos desenvolvedores.
  • Os 10% restantes, entretanto, podem ser extremamente úteis em fluxos de trabalho complexos (ou quando você estiver em uma enrascada). O próximo conceito que vamos abordar é "movendo trabalho por aí" -- em outras palavras, veremos as formas como o desenvolvedor pode dizer "eu quero este trabalho aqui, e aquele ali" de formas precisas, eloquentes e flexíveis.
  • Isso pode parecer muito, mas os conceitos são simples.
  • O primeiro comando desta série é o git cherry-pick. Ele é chamado da seguinte forma:
$ git cherry-pick <Commit1> <Commit2> <...>
  • Trata-se de uma forma bastante direta de dizer que você gostaria de copiar uma série de commits abaixo do seu local atual (HEAD). Eu pessoalmente amo o cherry-pick porque há muito pouca mágica envolvida e é fácil de entender o funcionamento.Vejamos uma demonstração!
  • Aqui está um repositório onde temos algum trabalho no ramo side que desejamos copiar para o master. Isso poderia ser obtido por meio de um rebase (que já aprendemos), mas vamos ver como o cherry-pick se sai. 0.w3pk7f515bo
$ git cherry-pick C2 C4

0.81fowvd2c4w

  • É isso! Queríamos os commits C2 e C4 e o git os inseriu logo abaixo de nós. Simples assim!
$ git cherry-pick C3 C4 C7

Introdução ao rebase interativo

  • O cherry-pick é ótimo quando você sabe de antemão quais commits você quer (e você sabe os hashes correspondentes) -- é difícil bater a simplicidade que ele oferece.
  • Mas e quando você não sabe quais commits você quer? Felizmente o git pode te ajudar nesta situação também! Podemos usar o rebase interativo para isso -- trata-se da melhor forma de rever uma série de commits sobre os quais você está prestes a fazer um rebase. Mergulhemos nos detalhes...
  • O rebase interativo é simplesmente o comando rebase com a opção -i. Se você incluir essa opção, o git abrirá uma interface para mostrar quais commits estão prestes a serem copiados abaixo do alvo do rebase. Ele também mostra os hashes e as mensagens dos commits, o que é ótimo para ter noção do que é o que.
  • No git "de verdade", a interface nada mais é que um arquivo aberto em um editor de texto (por exemplo o vim). Para os nossos propósitos, eu montei uma pequena janela que se comporta da mesma forma.
  • Quando a janela de rebase interativo abrir, você pode fazer 3 coisas diferentes:
    • Você pode reordenar os commits simplesmente mudando sua ordem na interface (na nossa janela isso significa arrastar e soltar com o mouse).
    • Você pode escolher simplesmente omitir alguns commits. Para isso, clique no botão pick -- deixar o pick desligado significa que você quer descartar o commit.
    • Por fim, você pode "esmagar" (fazer squash) nos commits. Infelizmente, nosso tutorial não será capaz de cobrir essa funcionalidade por alguns motivos logísticos, então vamos pular os detalhes disto. Em resumo, no entanto, o squash permite que você combine commits.
  • Ótimo! Vejamos um exemplo. Quando você clicar o botão, uma janela de rebase interativo se abrirá. Reordene alguns commits da forma como você preferir (ou sinta-se livre para desmarcar o pick de alguns) e veja o resultado! 0.ikuqyp8pqil
$ git rebase -i HEAD~4

0.cp9sa43knom

  • Boom! O Git copiou alguns commits exatamente da mesma forma que você os especificou na janela
$ git rebase -i HEAD~4

Pegando um único comando

  • Aqui está uma situação de acontece frequentemente com desenvolvedores: Estou tentando encontrar um bug, mas ele é escorregadio. Para auxiliar meu trabalho de detetive, eu coloco alguns comandos de debug e prints.
  • Todos esses comandos de debug e mensagens estão em seus próprios ramos. Finalmente eu encontro o bug, corrijo, e me regozijo!
  • O único problema é que agora eu preciso devolver o meu bugFix ao ramo master. Se eu simplesmente der um fast-forward no master, então o master terminará contendo todos os comandos de debug, o que é indesejável. Deve existir alguma outra forma...
  • Precisamos dizer ao git para copiar somente um dos commits. Esta situação é exatamente a mesma dos níveis anteriores a respeito de como mover trabalho -- podemos usar os mesmos comandos:
    • git rebase -i
    • git cherry-pick
  • Para alcançar o objetivo.
$ git rebase -i HEAD~3; git rebase bugFix master

Malabarismo com commits

  • Aqui está outra situação que acontece com bastante frequência. Você fez algumas mudanças (newImage), além de um outro conjunto de mudanças (caption) que são relacionadas, de forma que elas estão empilhadas uma após a outra no seu repositório.
  • O complicado é que algumas vezes você precisa fazer uma pequena modificação em um commit mais antigo. Neste caso, o pessoal do design quer que modifiquemos um pouco as dimensões da imagem introduzida em newImage, apesar de esse commit estar mais para trás no nosso histórico!!
  • Superaremos essa dificuldade fazendo o seguinte:
    • Reordenaremos os commits de forma que aquele que desejamos esteja no topo, com git rebase -i;
    • Usaremos o comando git commit --amend para fazer uma pequena modificação;
    • Vamos, então, reordenar os commits na mesma ordem que estavam anteriormente com git rebase -i;
    • Finalmente, moveremos o master para essa parte atualizada da árvore para finalizar o nível (usando o método de sua escolha).
  • Há muitas formas de alcançar o objetivo final (eu vejo o cherry-pick passando pela sua mente), e veremos mais delas depois, mas por enquanto foquemos nesta técnica.
  • Por último, preste atenção no estado do "objetivo" aqui -- como nós movemos os commits duas vezes, ambos ficam com um apóstrofo. Um apóstrofo adicional é colocado no commit que sofreu o amend, o que nos dá a forma final da árvore.
  • Tendo dito isto, posso avaliar a resposta baseado na estrutura e nas diferenças relativas de número de apóstrofos. Desde que o ramo master da sua árvore tenha a mesma estrutura, e o número de apóstrofos seja igual a menos de uma constante, darei a você todos os pontos para esta tarefa.
$ git rebase -i HEAD~2; git commit --amend; git rebase -i HEAD~2; git rebase caption master

Malabarismo com commits #2

  • Como você viu no nível anterior, usamos rebase -i para reordenar os commits. Uma vez que o commit que queríamos mudar estava no topo, pudemos facilmente usar o --amend e depois reordená-lo de volta para obter nossa ordem preferida.
  • O único problema aqui é que há muita reordenação ocorrendo, o que pode introduzir conflitos de rebase. Vamos dar uma olhada em outro método, usando o git cherry-pick.
  • Lembre-se que o git cherry-pick copiará um commit de qualquer lugar na árvore sob o HEAD (desde que esse commit não seja um ancestral do HEAD).
  • Aqui está uma demonstração para refrescar sua memória: 0.tycg1b5ysuk
$ git cherry-pick C2

0.h3oy7tdsw6

  • Ótimo! Vamos em frente.
  • Então, neste nível, vamos alcançar o mesmo objetivo de fazer "amend" no C2, mas evitaremos usar o rebase -i. Agora vou deixar com você a tarefa de descobrir como fazer!
  • Lembre-se, o número exato de apóstrofos (') nos commits não é importante, apenas as diferenças relativas.
$ git checkout master; git cherry-pick C2; git commit --amend; git cherry-pick C3

Tags no git

  • Como você aprendeu nas lições anteriores, ramos são fáceis de mover e geralmente vão se referindo a diferentes commits conforme você vai trabalhando no código. Ramos são facilmente mutáveis, frequentemente temporários, e estão sempre mudando.
  • Se este é o caso, você pode estar se perguntando se não existe uma forma de marcar permanentemente pontos históricos do projeto. Para coisas como grandes releases ou grandes merges, existe alguma forma de marcar commits com algo mais permanente que um ramo?
  • Você acertou a aposta, existe sim! As tags do Git foram criadas exatamente para esse caso de uso -- elas marcam de forma (relativamente) permanente certos commits como se fossem "pedras de kilometragem" ("milestones") em uma estrada, e você pode referenciá-las exatamente como faz com ramos.
  • O mais importante, no entanto, é que elas nunca se movem sozinhas quando novos commits são criados. Você pode fazer checkout em uma tag e então completar trabalho nessa tag -- tags existem como âncoras na árvore de commits que estão atreladas a certos pontos.
  • Vejamos como as tags se comportam na prática. Criemos uma tag em C1, que é nosso protótipo da versão 1: 0.d6s19j9m37v
$ git tag v1 C1

0.h564hh2e41o

  • Aqui! Bem fácil. Nós chamamos a tag de v1 e referenciamos o commit C1 explicitamente. Se você chamar o comando sem especificar um commit, o git vai usar seja lá qual commit para o qual o HEAD estiver apontando.
$ git tag v0 C1; git tag v1 C2; git checkout C2

Git describe

  • Devido ao fato de as tags servirem como "âncoras" tão boas no código, o Git tem um comando para descrever onde você está com relação à "âncora" (tag) mais próxima. Esse comando é chamado git describe!
  • O git describe pode ajudar a recuperar a sua orientação depois de você ter se movido muitos commits para trás ou para frente no histórico; isso pode acontecer depois de você completar um git bisect (uma busca para debug) ou quando se sentar no computador de um colega que acabou de voltar de férias.
  • O git describe é chamado da seguinte forma:
$ git describe <ref>
  • Onde <ref> é qualquer coisa que o git possa resolver como uma referência a um commit. Se você não especificar o ref, o Git usa simplesmente o commit atual (HEAD). A saída do comando é mais ou menos assim:
<tag>_<numCommits>_g<hash>
  • Onde tag é a tag ancestral mais próxima no histórico, numCommits é o número de commits de distância da tag, e <hash> é o hash do commit sendo descrito. Vejamos um exemplo rápido. Para a árvore abaixo: 0.cb0agvz3d6m
$ git tag v2 C3

0.feqn42b691h

  • O comando git describe master daria a saída:
v1_2_gC2
  • Enquanto git describe side daria:
v2_1_gC4

Fazendo mais de 9000 rebases

  • Cara, temos um monte de ramos aqui! Vamos fazer um rebase de todo o trabalho contido nesses ramos para o master.
  • No entanto, a cúpula da administração está tornando as coisas mais difíceis -- eles querem que os commits estejam todos em ordem sequencial. Isso significa que a nossa árvore final precisa ter o C7' por último, C6' acima disso, e assim por diante, tudo ordenado.
  • Se você fizer besteira, sinta-se livre para usar o comando reset para recomeçar do zero. Depois lembre de olhar nossa solução do gabarito para ver se consegue resolver a tarefa usando menos comandos
$ git rebase master bugFix; git rebase bugFix side; git rebase side another; git rebase another master

Multiplos pais

  • Assim como o modificador ~, o modificador ^ também aceita um número opcional depois dele.
  • Em vez de especificar o número de gerações a voltar (que é o que o ~ faz), o modificador no ^ especifica qual referência de pai a ser seguida a partir de um commit de merge. Lembre-se que commits de merge possuem múltiplos pais, então o caminho a seguir é ambíguo.
  • O Git normalmente subirá o "primeiro" pai de um commit de merge, mas especificar um número após o ^ muda esse comportamento padrão.
  • Basta de conversa, vejamos o operador em ação.
  • Aqui temos um commit de merge. Se fizermos checkout em master^ sem especificar um número, vamos seguir o primeiro pai acima do commit de merge (Em nossa visualização, o primeiro pai é aquele diretamente acima do commit de merge). 0.edpumhan8yr
$ git checkout master^

0.h130u6xfgo8

  • Fácil -- isso é aquilo com o que já estamos acostumados.
  • Agora vamos, em vez disso, especificar o segundo pai... 0.edpumhan8yr
$ git checkout master^2

0.1e3d2v7wa1h

  • Viu? Subimos para o outro pai.
  • Os modificadores ^ e ~ podem tornar a movimentação ao redor da árvore de commits muito poderosa: 0.dpqp34akhph
$ git checkout HEAD~; git checkout HEAD^2; git checkout HEAD~2

0.bi0vmo21kte

  • Rápido como a luz!
  • Ainda mais louco, esses modificadores podem ser encadeados em conjunto! Veja só: 0.q28ss7fpsb
$ git checkout HEAD~^2~2

0.731dori8fsy

  • O mesmo movimento que o anterior, mas tudo em um único comando.
$ git branch bugWork master^^2^

Espaguete de ramos

  • Uhuuuuu Nelly! Temos um belo de um objetivo para alcançar neste nível. Temos aqui um master que está alguns commits atrás dos ramos one, two e three. Seja lá por qual razão, precisamos atualizar esses três outros ramos com versões modificadas dos últimos commits do master.
  • O ramo one precisa de uma reordenação e da exclusão do C5. O two precisa apenas de reordenação. O three precisa de um único commit!
  • Vamos deixar você descobrir como resolver esta tarefa -- mas não deixe de ver a nossa solução depois com o comando show solution.
$ git checkout one; git cherry-pick C4 C3 C2; git checkout two; git cherry-pick C5 C4 C3 C2; git rebase C2 three
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment