Desfazendo um 'git push'


591

Aqui está o que eu fiz no meu ramo supostamente estável ...

% git rebase master
First, rewinding head to replay your work on top of it...
Fast-forwarded alpha-0.3.0 to master.
% git status
# On branch alpha-0.3.0
# Your branch is ahead of 'origin/alpha-0.3.0' by 53 commits.
#
nothing to commit (working directory clean)
% git push
Fetching remote heads...
  refs/
  refs/heads/
  refs/tags/
  refs/remotes/
'refs/heads/master': up-to-date
updating 'refs/heads/alpha-0.3.0'
  from cc4b63bebb6e6dd04407f8788938244b78c50285
  to   83c9191dea88d146400853af5eb7555f252001b0
    done
'refs/heads/unstable': up-to-date
Updating remote server info

Isso foi tudo um erro, como eu percebi mais tarde. Gostaria de desfazer todo esse processo e reverter o ramo alpha-0.3.0 de volta ao que era.

O que devo fazer?



4
Na verdade, não é a mesma situação: desfazer uma rebase é um cenário de repositório local, desfazer um push git envolve um repositório remoto e pode ser mais complicado, dependendo do acesso que você possui.
CB Bailey

Steen - você está certo - eu provavelmente deveria ter, suponho. Eu imaginei que o repositório abençoado que todos extraem é mais uma tarefa administrativa e, portanto, pertence aqui, onde o git geral do lado do cliente é uma questão de stackoverflow.
Cyrus

Esclarecimento rápido - Acho que se você se referir a um commit git com um valor parcial de hash, o git assumirá que você está falando do commit cujo hash começa com essa string?
precisa

Respostas:


944

Você precisa garantir que nenhum outro usuário deste repositório esteja buscando as alterações incorretas ou tentando construir sobre as confirmações que você deseja remover porque está prestes a retroceder o histórico.

Então você precisa 'forçar' empurrar a referência antiga.

git push -f origin last_known_good_commit:branch_name

ou no seu caso

git push -f origin cc4b63bebb6:alpha-0.3.0

Você pode ter receive.denyNonFastForwardsdefinido no repositório remoto. Se for esse o caso, você receberá um erro que inclui a frase [remote rejected].

Nesse cenário, você precisará excluir e recriar a ramificação.

git push origin :alpha-0.3.0
git push origin cc4b63bebb6:refs/heads/alpha-0.3.0

Se isso não funcionar - talvez porque você tenha receive.denyDeletesdefinido, é necessário ter acesso direto ao repositório. No repositório remoto, você deve executar algo como o seguinte comando de encanamento.

git update-ref refs/heads/alpha-0.3.0 cc4b63bebb6 83c9191dea8

16
Uma resposta perfeita e bem explicada - muito obrigado. Para qualquer um que tropeçar nisso, por razões acadêmicas, tentei as duas primeiras duas abordagens e ambas funcionaram - obviamente, se a primeira funcionar, é a abordagem mais limpa. Se eu te recompor 10 vezes Charles, eu o faria. :)
Cyrus

139
Para referência rápida, a primeira linha aqui égit push -f origin last_known_good_commit:branch_name
philfreo

5
origem git push -f cc4b63bebb6: alpha-0.3.0 => este me ajudou, Nota alpha-0.3.0 é o nome do ramo e cc4b63bebb6 é o ID de confirmação ao qual queremos reverter. então, após executar este comando, estaremos no cc4b63bebb6 commit id.
kumar

22
Essa solução é altamente perigosa se você estiver trabalhando em um repositório compartilhado. Como prática recomendada, todas as confirmações enviadas para um repositório remoto compartilhado devem ser consideradas "imutáveis". Use 'git revert': kernel.org/pub/software/scm/git/docs/…
Saboosh

1
jww - comparado a tudo o mais, o git é a ferramenta de controle de fonte mais rica em recursos e eficiente disponível. Cada equipe usa de maneira diferente. Vale a pena passar um fim de semana brincando com um repositório novo e passando por todos os cenários comuns. Depois de passar algum tempo trabalhando com ele, o desenvolvimento é muito menos estressante.
user1491819

165

Eu acredito que você também pode fazer isso:

git checkout alpha-0.3.0
git reset --hard cc4b63bebb6
git push origin +alpha-0.3.0

Isso é muito semelhante ao último método, exceto que você não precisa se preocupar com o repo remoto.


9
Isso funcionou para mim também, mas vale a pena notar que isso "reescreverá" o histórico no controle remoto. Pode ser o que você quer, mas pode não ser!
Tom

3
+1 nesta resposta que realmente me ajudou. Eu também queria adicionar (e esclarecer as coisas) que o ID de confirmação (que vem depois do --hardparâmetro " ") deve ser o ID de qualquer confirmação que você deseja redefinir para sua ramificação.
Michael Dautermann 27/07/2012

1
Reescrevi a história muito bem ... qualquer um que pudesse ter feito as alterações, eu apenas me assegurei de que fizessem git reset --hard [commit_id]isso, para não mexermos no continuum espaço-tempo.
Alien Life Form

9
Qual é o + para "git push origin + alpha-0.3.0"?
jpierson

1
O @jpierson +força o envio, da mesma forma que -f(mas um pouco diferente: stackoverflow.com/a/25937833/1757149 ). Sem ele, se você tentar git push origin alpha-0.3.0o impulso irá falhar: Updates were rejected because the tip of your current branch is behind.
A__ 28/11

106

git revert é menos perigoso do que algumas das abordagens sugeridas aqui:

prompt> git revert 35f6af6f77f116ef922e3d75bc80a4a466f92650
[master 71738a9] Revert "Issue #482 - Fixed bug."
 4 files changed, 30 insertions(+), 42 deletions(-)
prompt> git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)
prompt>

Substitua 35f6af6f77f116ef922e3d75bc80a4a466f92650 por seu próprio commit.


2
Como crio o ID 35f6af6f77f116ef922e3d75bc80a4a466f92650? Essa resposta seria melhor se você pudesse explicar isso.
Volomike

2
@Volomike (e pesquisando devs do futuro), esta questão descreve várias maneiras de obtê-la: controle de versão e pergunta de hash no SO
Jaime

Esta é a resposta certa, porque com o "git reset" você não poderá fazer o push (as atualizações foram rejeitadas porque a ponta do seu ramo atual está atrás da contraparte remota) ou você precisará forçar a atração que não está realmente limpa.
Thomas Decaux

Isso estava funcionando para mim. No entanto, tenha cuidado, pois a reversão reverterá todas as alterações nos arquivos locais.
user1941537

Optei por essa abordagem várias vezes, mas também uso o git rebase -i <id-before-last-good-commit> para fazer uma rebase interativa e limpar o histórico conforme sugerido aqui, stackoverflow.com/questions/5189560/… .
Ernesto Allely

35

A solução aceita (do @charles bailey) é altamente perigosa se você estiver trabalhando em um repositório compartilhado.

Como prática recomendada, todas as confirmações enviadas para um repositório remoto compartilhado devem ser consideradas "imutáveis". Use 'git revert': http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#fixing-mistakes

https://git-scm.com/book/be/v2/Git-Basics-Undoing-Things


Quais são exatamente as instruções que você está prescrevendo? Você parece ter apenas links antigos.
JWW

32

Uma maneira de fazer isso sem perder as alterações desejadas:

git reset cc4b63b 
git stash
git push -f origin alpha-0.3.0
git stash pop

Depois, você pode escolher os arquivos que deseja enviar


19

Outra maneira de fazer isso:

  1. crie outro ramo
  2. faça o checkout do commit anterior nesse ramo usando "git checkout"
  3. empurre o novo ramo.
  4. exclua o ramo antigo e pressione o botão excluir (use git push origin --delete <branch_name>)
  5. renomeie o novo ramo para o ramo antigo
  6. empurre novamente.

2
Este olha como uma solução real quando você tem commits já erradas em repo
Illarion Kovalchuk


11

Desfazer várias confirmações git reset --hard 0ad5a7a6 (Apenas forneça o hash SHA1 de confirmação)

Desfazer a última confirmação

git reset --hard HEAD ~ 1 (as alterações no último commit serão removidas) git reset --soft HEAD ~ 1 (as alterações no último commit estarão disponíveis como modificações locais não confirmadas)


9

Cenário 1 : Se você deseja desfazer a última confirmação, diga 8123b7e04b3, abaixo está o comando (isso funcionou para mim):

git push origin +8123b7e04b3^:<branch_name>

A saída se parece abaixo:

Total 0 (delta 0), reused 0 (delta 0)
To https://testlocation/code.git
 + 8123b7e...92bc500 8123b7e04b3^ -> master (forced update)

Informações adicionais: Cenário 2 : Em algumas situações, você pode querer reverter o que acabou de desfazer (basicamente desfaz o desfazer) através do comando anterior e, em seguida, use o comando abaixo:

git reset --hard 8123b7e04b3

Resultado:

HEAD is now at cc6206c Comment_that_was_entered_for_commit

Mais informações aqui: https://github.com/blog/2019-how-to-undo-almost-anything-with-git


O cenário 1 deve ser a resposta aceita, pois a pergunta não especificou qual confirmação será excluída. A resposta aceita exclui apenas a última confirmação. Esta resposta exclui qualquer confirmação.
Dominic Cerisano

0

As respostas existentes são boas e corretas, no entanto, e se você precisar desfazer o pushmas:

  1. Você deseja manter as confirmações localmente ou deseja manter alterações não confirmadas
  2. Você não sabe quantos commit você acabou de enviar

Use este comando para reverter a alteração para ref:

git push -f origin refs/remotes/origin/<branch>@{1}:<branch>

-2

Se você deseja ignorar o último commit que você acabou de enviar na ramificação remota: isso não remove o commit, mas apenas o ignora movendo o ponteiro git para o commit anteriormente, referido por HEAD ^ ou HEAD ^ 1

git push origin +HEAD^:branch

Mas se você já enviou esse commit e outros já fizeram o branch. Nesse caso, reescrever o histórico de sua ramificação é indesejável e você deve reverter esse commit:

git revert <SHA-1>
git push origin branch

1
sim! isso funcionou como um encanto ao trabalhar com o github. obrigado.
cukabeka

A pergunta é sobre "push", então diz respeito à ramificação remota. Não para mover a cabeça sobre um commit o que significa ignorar o último commit empurrou apenas fazer isso: git empurrar origem + CABEÇA ^: your_branch
mkebri
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.