git push –force and how to deal with it

Você já se viu numa situação em que um comando de git errado causou estragos no repo do seu projeto? As pessoas cometem erros, e às vezes esses erros podem custar horas do tempo da sua equipe. Neste tutorial, vamos mostrar-lhe como se recuperar de um infeliz git push --force rapidamente.

Não vamos ficar demasiado confiantes. Mais cedo ou mais tarde, isto vai acontecer. Enquanto trabalha com vários controles remotos no mesmo repositório git, você irá eventualmente git push --force em master (ou outro ramo importante que nunca deve ser mexido).

Isso pode acontecer, por exemplo, ao implantar com Deis ou Heroku que usam controles remotos git separados para construir e implantar uma aplicação. Após um longo dia de trabalho, é incrivelmente fácil executar git push --force em vez do habitual git push --force deis master.

Oops! Num piscar de olhos, os seus colegas de equipa perderam todo o seu último trabalho. Hora de enfrentar a sua raiva.

No entanto, como nos diz um excelente guia, NÃO PAIZE! O bom é que você usa o git, e isso significa que tudo pode ser corrigido.

Cenário do melhor caso: alguém que está trabalhando no mesmo código puxou uma versão recente do master pouco antes de você quebrá-lo. Então tudo que você tem que fazer é entrar no chat da sua equipe e pedir a essa pessoa para forçar suas mudanças recentes.

Se você tiver sorte, o repositório local deles terá o histórico completo de commits, seu erro será sobrescrito com código novo, e nada será perdido. Mas e se você não tiver essa sorte? Então, leia!

Caso 1: Você foi a última pessoa a empurrar para dominar antes do erro

Bom notícia! Você tem tudo o que precisa para desfazer o seu erro diante dos seus próprios olhos. Apenas não feche ou limpe o seu terminal. Primeiro, entre no chat da sua equipa e confesse os seus pecados. Peça às pessoas para não mexerem no repo no próximo minuto, mais ou menos, enquanto você está consertando as coisas.

Na saída do comando git push --force na sua shell procure por uma linha que se pareça com esta:

 + deadbeef...f00f00ba master -> master (forced update)

O primeiro grupo de símbolos (que se parece com o prefixo SHA de um commit) é a chave para o resgate. deadbeef é o seu último bom commit para o ramo master pouco antes de você infligir danos.

Então tudo o que você precisa é… forçar o push (combatendo fogo com fogo!) este commit de volta para o ramo master, no topo um mau.

$ git push --force origin deadbeef:master

Congratulações! Você salvou o dia. Agora é hora de aprender com seus erros.

Fase 2: mestre foi trocado por outra pessoa antes de você fazer asneira

Então, pouco antes de você fazer git push --force alguém tinha fechado um monte de pedidos de puxar, e o master agora não se parece nada com a sua cópia local. Você não pode mais fazer git push --force sha1:master porque você não tem compromissos locais recentes (e você não pode obtê-los com git fetch porque eles não pertencem mais a nenhuma filial). Mesmo assim, mantenha a calma e peça aos seus colegas de equipe para ficarem longe do controle remoto por um tempo.

Nós nos beneficiaremos do fato de que o GitHub não remove commits inalcançáveis imediatamente. Claro, você também não pode ir buscá-los, mas há uma alternativa.

Note que ele só funcionará se você estiver “observando” o repositório, para que tudo que acontece nele apareça em um feed exibido na página principal do seu GitHub. Abra esse feed e procure por algo assim:

an hour agoUsername pushed to master at org/repo - deadbeef Implement foo - deadf00d Fix bar

Agora você pode:

  • Componha uma URL https://github.com/org/repo/tree/deadbeef, onde deadbeef é um hash do último bom compromisso para o ramo danificado;
  • Abra o comutador de ramos/tags na interface web do GitHub;
  • >

Alternador de ramo/tag switcher GitHub

Alternador de ramo/tager GitHub

>
  • Criar um nome para um novo ramo temporário (e.g., master-before-force-push);
  • Clique em “Criar ramo”.

Agora você pode ir buscar todos os commits faltantes:

$ git fetchFrom github.com:org/repo * master-before-force-push -> origin/master-before-force-push

Seu problema agora está reduzido ao descrito em um exemplo anterior:

$ git push --force origin origin/master-before-force-push:master

Se você ainda precisa do seu trabalho para estar no master, apenas rebase em cima dele:

$ git rebase origin/master

Como evitar tal desastre no futuro

  1. GitHub e GitLab têm uma característica chamada “ramos protegidos”.” Marca master, develop, stable, ou quaisquer outros ramos cruciais como protegidos e ninguém poderá forçar o empurrão para dentro deles. É sempre possível desproteger temporariamente um ramo se você realmente precisar sobrescrever o histórico.

    Ler os documentos do GitHub para detalhes.

  2. Em vez de --force opção, use --force-with-lease. Ele irá parar a operação de empurrar se alguém tiver empurrado para o mesmo ramo enquanto você estava trabalhando nele (e não puxou nenhuma mudança).

    Veja este artigo da Atlassian.

  3. Criar aliases para comandos que usam git push --force para prevenir ações destrutivas por acidente:

    # ~/.gitconfig deploy = "!git push --force deis \"$(git rev-parse --abbrev-ref HEAD):master\""

    Ler o capítulo ProGit sobre aliases.

  4. Nunca faça seus experimentos no ramo principal de um repositório! git checkout -b experiments é o seu melhor amigo.

  5. Dica de ProGit: git push tem muitas opções. --force e --all trabalham em conjunto especialmente bem. Você pode usar esta combinação ao retornar ao projeto após vários meses de inatividade. Experimente se você estiver se sentindo extra aventureiro!

Leave a Reply