Excluir confirmações de uma ramificação no Git


3233

Gostaria de saber como excluir uma confirmação.

Por delete, quero dizer, é como se eu não fizesse esse commit e, quando eu fizer um push no futuro, minhas alterações não serão enviadas para o branch remoto.

Eu li a ajuda do git e acho que o comando que devo usar é git reset --hard HEAD. Isso está correto?


41
Eu acho que isso não é uma duplicata do Git desfazer a última confirmação , pois pergunta como excluir qualquer confirmação de um ramo. Eu também acho que algumas das respostas realmente abordam essa questão. Todos eles rebobinam as últimas confirmações, não cherry-picke deleteuma única confirmação que ocorreu há algum tempo.
Chris

12
@ Chris, a resposta com git rebase -i HEAD~10aborda a questão, pois permite que você escolha arbitrariamente as confirmações para excluir. O Git aplica as confirmações no intervalo especificado por você, ignorando as confirmações removidas do log. Eu usei esse comando hoje para me livrar do segundo e terceiro commit mais recentes do meu repositório, mantendo o primeiro. Concordo que nenhuma das outras respostas seja satisfatória.
MST

@MST sim, eu deveria ter dito, não das opções no endereço resposta aceita esta pergunta, mas você está absolutamente certo - esse comando parece funcionar
Chris

Respostas:


4127

Cuidado: git reset --hard EXCLUIRÁ SUAS MUDANÇAS DE DIRETÓRIO DE TRABALHO . Certifique-se de guardar quaisquer alterações locais que você deseja manter antes de executar este comando.

Supondo que você esteja sentado nesse commit, esse comando o deixará louco ...

git reset --hard HEAD~1

Os HEAD~1meios que o commit antes da cabeça.

Ou, você pode olhar para a saída de git log, encontrar o ID da confirmação da qual você deseja fazer backup e, em seguida, faça o seguinte:

git reset --hard <sha1-commit-id>

Se você já o empurrou, precisará fazer um empurrão forçado para se livrar dele ...

git push origin HEAD --force

No entanto , se outros tiverem conseguido, é melhor iniciar um novo ramo. Porque quando eles puxam, isso simplesmente o mesclará no trabalho deles, e você o empurrará novamente.

Se você já enviou, pode ser melhor usar git revert, criar uma confirmação de "imagem em espelho" que desfará as alterações. No entanto, ambas as confirmações estarão no log.


FYI - git reset --hard HEADé ótimo se você quiser se livrar do WORK IN PROGRESS. Ele o redefinirá para a confirmação mais recente e apagará todas as alterações na sua árvore e índice de trabalho.


Por fim, se você precisar encontrar um commit que você "excluiu", ele normalmente estará presente, a git reflogmenos que você tenha coletado lixo no seu repositório.


59
HEAD~1ou apenas HEAD^. Se você pressionou, você deve usar git revert.
Jakub Narębski 27/08/09

13
Obviamente, você também pode usar HEAD~npara "voltar" nconfirma da sua cabeça. Talvez a partir deste ponto você possa interpretar ... --hard HEADtambém como HEAD~0=> excluir trabalho em andamento.
nuala

13
@ beamrider9 imho git rebase é quase sempre a melhor maneira de excluir commits (como descrito na resposta de Greg Hewgill) - até porque rebase inclui de fato um grande aviso de que você estará excluindo coisas 4realz.
Noah Sussman

20
isso não exclui as alterações da árvore de confirmação. O OP solicitou um commit já feito. Se você reset --harde verificar log --oneline --allas confirmações ainda permanecem na árvore. Como excluímos esses commits da árvore? Obrigado.
IGbanam 17/03

17
use reset --softpara excluir o commit local SEM reverter o trabalho em andamento!

704

Se você ainda não enviou o commit em nenhum lugar, pode git rebase -iremovê-lo. Primeiro, descubra até que ponto esse commit está (aproximadamente). Então faça:

git rebase -i HEAD~N

Os ~Nmeios rebase os últimos Ncommits ( Ndevem ser um número, por exemplo HEAD~10). Em seguida, você pode editar o arquivo que o Git apresenta para você para excluir a confirmação incorreta. Ao salvar esse arquivo, o Git reescreverá todas as confirmações a seguir, como se a que você excluiu não existisse.

O Git Book tem uma boa seção sobre rebasing com fotos e exemplos.

Tenha cuidado com isso, porém, porque se você mudar algo que você ter empurrado em outros lugares, será necessária outra abordagem a menos que você está planejando fazer um empurrão vigor.


2
Nota: Se ocorrer alguma mesclagem --no-ff no último lote de confirmações, o rebase os cortará :( Isso é mencionado em -p nesta página . O problema é que, se você substituir -i por -p, você não conseguir que pop-up com as opções para "editar este cometer, sqush que um", etc etc alguém sabe a solução?
Bukov

4
E se você empurrou? (apenas me usando o repo remoto)
Costa

6
@ Costa que você pode usar push -fpara forçar o envio e substituir a filial remota pela local. Se for apenas seu próprio repositório remoto, não há problema. O problema começa se alguém tiver buscado nesse meio tempo.
Greg Hewgill

3
Eu adicionei e comprometi um arquivo de dados que era muito grande para o GitHub (sim, provavelmente não deveria estar no repositório de origem de qualquer maneira; tudo bem). Quando tentei enviar por push, o GitHub recusou por causa do arquivo muito grande. Tudo que eu queria fazer era desfazer esse commit, enquanto salvava alguns outros commits não relacionados que se seguiram. O git rebase -i HEAD~5comando era exatamente o que eu precisava para remover completamente esse commit do meu repositório local! Obrigado!
aldo

4
@dumbledad: Com rebase -i, as alterações correspondentes à confirmação excluída não são preservadas.
Greg Hewgill

517

Outra possibilidade é um dos meus comandos favoritos pessoais:

git rebase -i <commit>~1

Isso iniciará o rebase no modo interativo -ino momento imediatamente anterior ao commit que você deseja executar. O editor começará listando todos os commits desde então. Exclua a linha que contém a confirmação que você deseja eliminar e salve o arquivo. O rebase fará o restante do trabalho, excluindo apenas esse commit e reproduzindo todos os outros novamente no log.


3
thx, btw se você tiver algum problema (como commits vazios), você pode usargit rebase --continue
realgt 28/12

8
Ainda mais fácil: git rebase -i HEAD~1
mmell 10/09

2
Wowzers. git rebase -i HEAD~1realmente limpou muito o repo! É difícil dizer exatamente o que fez, mas a coisa toda parece muito mais organizada. Um pouco alarmante, na verdade.
Charles Wood

7
Eu acho que vale a pena notar que o commit não é obliterado, apenas removido da lista. Se você errar, poderá recuperar o commit usando o reflog .
Zaz

6
A exclusão da linha é igual a d / drop?
Leo

345

Estou acrescentando esta resposta porque não vejo por que alguém que acabou de tentar cometer trabalho desejaria excluir todo esse trabalho por causa de algum erro ao usar o Git!

Se você deseja manter seu trabalho e apenas 'desfazer' esse comando de confirmação (você capturou antes de pressionar para repo):

git reset --soft HEAD~1

Não use o sinalizador --hard, a menos que queira destruir seu trabalho em andamento desde a última confirmação.


5
Aqui está um exemplo do porquê: você faz um pequeno trabalho em um servidor de desenvolvimento que confirma. Acontece que esse servidor não tem acesso HTTPS de saída; portanto, você não pode enviar a confirmação em nenhum lugar. É mais fácil fingir que nunca aconteceu e refazer o patch da sua máquina local.
precisa saber é o seguinte

1
@KarthikBose sempre haveria o reflog. mesmo após git reset --hard HEAD~1a confirmação mais recente anterior estar disponível via reflog (até que você expire); veja também aqui: gitready.com/intermediate/2009/02/09/…
codeling

4
Obrigado. Esta resposta deve ter uma classificação mais alta ou ser incluída na resposta aceita. Excluindo uma confirmação! = Revertendo uma confirmação.
precisa saber é o seguinte

2
@ RandolphCarter: você ainda perderá quaisquer alterações não confirmadas.
precisa saber é o seguinte

7
@ Rob, um exemplo é quando você acidentalmente confirma um arquivo que contém um segredo (por exemplo, uma senha) que nunca deve estar no controle de origem. A consolidação local deve ser destruída , não apenas desfeita, para nunca ser enviada ao servidor.
amigos estão dizendo sobre bob

142

Removendo um commit inteiro

git rebase -p --onto SHA^ SHA

Obviamente, substitua "SHA" pela referência da qual você deseja se livrar. O "^" nesse comando é literal.

http://sethrobertson.github.io/GitFixUm/fixup.html#change_deep


26
como posso votar mais esta resposta ??? as outras soluções estão apenas mostrando como fazê-lo interativamente ou remover os principais commit.
Ribamar

5
-p, --preserve-merges Recrie confirmações de mesclagem em vez de nivelar o histórico reproduzindo confirmações introduzidas por uma consolidação de mesclagem. As resoluções de conflito de mesclagem ou emendas manuais para mesclar confirmações não são preservadas.
raittes

5
Esta é a resposta exata real
Hamman Samuel

9
Ele diz: "substitua SHA pela referência da qual você deseja se livrar", mas a linha tem SHA lá duas vezes. Aqui está o que eu fiz. git rebase -p --onto 5ca8832c120 ^ 5ca8832c120 Mas nada mudou. Devo usar o mesmo SHA duas vezes? Caso contrário, qual é o SHA do commit a ser removido e qual deve ser o outro SHA?
Rubicksman 14/05/19

3
WOW, funcionou perfeitamente! Essa deve ser a resposta aceita!
Liran H

51

Se você não publicou alterações, para remover a confirmação mais recente, você pode fazer

$ git reset --hard HEAD^

(observe que isso também removeria todas as alterações não confirmadas; use com cuidado).

Se você já publicou o commit a ser excluído, use git revert

$ git revert HEAD

Isso não deu certo. Quando eu git log, tudo ainda está lá, não importa por que eu faça isso, apenas adiciona mais confirmações. Eu quero limpar a história.
Costa

@ Costa: O que não funcionou (ou seja, qual versão você usou) e como você git log?
Jakub Narębski

Eu tentei quase tudo nesta sessão de perguntas e respostas. (Eu tentei CABEÇA revert git, mais recentemente) Meu git log:tree = log --all --graph --format=format:'%C(bold blue)%h%C(reset) %C(dim black)%s%C(reset)%C(bold red)%d%C(reset) %C(green)by %an, %ar%C(reset)'
Costa

1
Eu só quero excluir os commits (como se eles nunca existissem). Eu saí em uma aventura estranha de codificação, com vários novos commits, e tudo acabou sendo lixo. Como posso apagar os do meu log do git?
Costa

2
Puta merda, algo magicamente fez exatamente o que eu queria ... qual desses comandos fez isso? !!?!
Costa

45

Digamos que queremos remover as confirmações 2 e 4 do repositório.

commit 0 : b3d92c5
commit 1 : 2c6a45b
commit 2 : <any_hash>
commit 3 : 77b9b82
commit 4 : <any_hash>

Nota: Você precisa ter direitos de administrador sobre o repositório, pois está usando --harde -f.

  • git checkout b3d92c5 Finalize o último commit utilizável.
  • git checkout -b repair Crie uma nova ramificação para trabalhar.
  • git cherry-pick 77b9b82 Execute o commit 3.
  • git cherry-pick 2c6a45b Execute o commit 1.
  • git checkout master Mestre do Google Checkout.
  • git reset --hard b3d92c5 Redefina o mestre para a última confirmação utilizável.
  • git merge repair Mesclar nossa nova filial ao mestre.
  • git push -f origin master Empurre o mestre para o repositório remoto.

1
último passo deve ser, git push -f origin masternão há opção--hard
Vivex 15/01

2
Eu acho que commit 0é mais velho que commit 1. Por favor, você poderia me dizer por que primeiro executar commit 3(por cherry-pick) e depois por commit 1? Após o checkout de b3d92cd( commit 0), eu esperaria uma escolha de cereja commit 1, então commit 3. Obrigado.
precisa

@JarekC Eu acho que o mais alto cometer é o mais novo cometer aqui, a menos que eu estou vendo algo de errado ...
Jeff Huijsmans

41
git reset --hard commitId

git push <origin> <branch> --force

PS: CommitId refere-se àquele ao qual você deseja reverter


git push --force <origin> <branchName>. como sem mencionar o nome do ramo, ele pode alterar todos os arquivos no controle remoto.
sheelpriy

39

Histórico de alterações forçadas

Supondo que você não queira apenas excluir o último commit, mas você deseja excluir os commit específicos dos últimos n commit, vá com:

git rebase -i HEAD~<number of commits to go back>, portanto, git rebase -i HEAD~5se você deseja ver os últimos cinco confirmados.

Em seguida, no editor de texto, altere a palavra pickpara droppróximo a cada confirmação que você deseja remover. Salve e saia do editor. Voila!

Histórico de alterações de forma aditiva

Tente git revert <commit hash>. Reverter criará uma nova confirmação que desfaz a confirmação especificada.


droppalavra-chave não está definida. Para excluir uma confirmação, remova a linha inteira.
perfil completo de Shayan Salehian

1
Para mim, drop foi definido como uma palavra-chave, mas fazer um drop não pareceu remover o commit do histórico. Remover a linha do rebase interativo, no entanto.
23619 Adam Parkin

Isso é exatamente o que eu precisava. Funciona bem; obrigado!
diekunstderfuge 6/03

30

Se você deseja corrigir o seu commit mais recente, pode desfazer o commit e desestabilizar os arquivos nele, fazendo:

git reset HEAD~1

Isso retornará seu repositório ao seu estado antes dos comandos git add que prepararam os arquivos. Suas alterações estarão no seu diretório de trabalho. HEAD ~ 1 refere-se ao commit abaixo da ponta atual do ramo.

Se você deseja cancelar a confirmação de N, mas mantenha as alterações de código no seu diretório de trabalho:

git reset HEAD~N

Se você deseja se livrar da sua confirmação mais recente e não deseja manter as alterações no código, é possível fazer uma redefinição "física".

git reset --hard HEAD~1

Da mesma forma, se você deseja descartar os últimos N commit e não deseja manter as alterações no código:

git reset --hard HEAD~N

22
git rebase -i HEAD~2

Aqui '2' é o número de confirmações que você deseja refazer.

'git rebase -i HEAD`

se você quiser refazer todas as confirmações.

Então você poderá escolher uma dessas opções.

p, pick = use commit

r, reword = use commit, but edit the commit message

e, edit = use commit, but stop for amending

s, squash = use commit, but meld into previous commit

f, fixup = like "squash", but discard this commit's log message

x, exec = run command (the rest of the line) using shell

d, drop = remove commit

Essas linhas podem ser reordenadas; eles são executados de cima para baixo. Se você remover uma linha aqui, esse compromisso será perdido. No entanto, se você remover tudo, a recuperação será cancelada. Observe que as confirmações vazias são comentadas

Você pode simplesmente remover essa confirmação usando a opção "d" ou Removendo uma linha que tenha sua confirmação.


Na versão mais recente do git, não há mais opção d . Você só precisa remover as linhas com confirmações de rebase para excluí-las.
Oleg Abrazhaev

17

Para excluir na ramificação local, use

git reset --hard HEAD~1

Para excluir em uma ramificação remota, use

git push origin HEAD --force

12

[Resposta rápida]

Você tem muitas alternativas, por exemplo:

  • Alternativa 1:

    git rebase -i <YourCommitId>~1
    

    Altere YourCommitId pelo número do commit ao qual você deseja reverter.

  • Alternativa 2:

    git reset --hard YourCommitId
    git push <origin> <branch> --force
    

    Altere YourCommitId pelo número do commit ao qual você deseja reverter.

    Não recomendo esta opção porque você pode perder seu trabalho em andamento.

  • Alternativa 3:

    git reset --soft HEAD~1
    

    Você pode manter seu trabalho e apenas desfazer o commit.


agradecimento agradecimento agradecimento (Y)
Habib Rehman

11

Fonte: https://gist.github.com/sagarjethi/c07723b2f4fa74ad8bdf229166cf79d8

Excluir a última confirmação

Por exemplo, seu último commit

origem do push do git + aa61ab32 ^: master

Agora você deseja excluir esse commit e, em seguida, uma maneira fácil de fazer isso a seguir

Passos

  1. Primeiro redefina a ramificação para o pai da confirmação atual

  2. Empurre-o com força para o controle remoto.

git reset HEAD^ --hard

git push origin -f

Para confirmação específica, você deseja redefinir está seguindo

git reset bb676878^ --hard

git push origin -f

9

Aqui está outra maneira de fazer isso:

Faça o checkout da filial que você deseja reverter e, em seguida, redefina sua cópia de trabalho local de volta para a confirmação de que você deseja ser a mais recente no servidor remoto (tudo depois que ela se despedir). Para fazer isso, no SourceTree, clique com o botão direito do mouse no botão e selecione "Redefinir BRANCHNAME para este commit". Eu acho que a linha de comando é:

git reset --hard COMMIT_ID

Como você acabou de efetuar o check-out de sua filial remotamente, não haverá alterações locais para se preocupar em perder. Mas isso os perderia se você o fizesse.

Em seguida, navegue até o diretório local do seu repositório e execute este comando:

git -c diff.mnemonicprefix=false -c core.quotepath=false \
push -v -f --tags REPOSITORY_NAME BRANCHNAME:BRANCHNAME

Isso apagará todas as confirmações após a atual em seu repositório local, mas apenas para essa ramificação.


9

O erro:

I git rebase -i --root'ed meu ramo, ignorantemente pensando que eu poderia reformular o primeiro cometer diferindo do master (o GitHub para Windows modo de exibição padrão é a comparação de dominar, escondendo sua totalidade).

Eu cresci uma barba no Vale do Silício, enquanto mais de 900 commits se carregavam no Sublime. Saindo sem alterações, carreguei minha bateria e comecei a fazer a barba, pois todos os mais de 900 indivíduos se comprometem com indiferença - redefinindo seus tempos de consolidação agora.

Determinado a vencer o Git e preservar os tempos originais, excluí este repositório local e clono novamente no controle remoto.

Agora, havia adicionado novamente o commit desnecessário mais recente ao mestre que eu desejava remover, e assim procedi.

Esgotando as opções:

Eu não queria git revert- isso criaria um commit adicional, dando ao Git a vantagem.

git reset --hard HEADnão fez nada, depois de verificar o reflog, o último e único HEADfoi o clone - Git vence.

Para obter o SHA mais recente, verifiquei o repositório remoto no github.com - vitória menor.

Depois que o pensamento git reset --hard <SHA>funcionou, atualizei outro ramo para dominar e 1 ... 2 ... poof! o commit estava de volta - Git vence.

Voltando ao mestre, hora de tentar git rebase -i <SHA>, em seguida, remova a linha ... sem sucesso, é triste dizer. " Se você remover uma linha aqui, esse compromisso será perdido ". Ah ... encobrindo o novo recurso, troll o n00b nas notas de versão 2.8.3 .

A solução:

git rebase -i <SHA>então d, drop = remove commit.

Para verificar, fiz check-out para outro ramo, e pronto - sem esconder o compromisso de buscar / puxar do mestre.

https://twitter.com/holman/status/706006896273063936

Bom dia para você.


8

Todos os comandos acima restauram o estado da sua árvore de trabalho e indexam como estavam antes de confirmar, mas não restauram o estado do repositório. Se você observar, a confirmação "removida" não é realmente removida, simplesmente não é a que está na ponta do ramo atual.

Eu acho que não há como remover um commit com comandos de porcelana . A única maneira é removê-lo do log e reflog e, em seguida, executar a git prune --expire -now.


1
A ordem na qual as respostas são mostradas no StackOverflow não é fixa. Por favor, não consulte "Todos os comandos acima". Faça sua própria resposta independente.
Pascal Cuoq

Esta resposta não está totalmente correta. git prune é realmente um dos comandos "porcelana" . Além disso, é raro que você queira limpar completamente o reflog (um caso de uso é remover informações confidenciais do seu repositório, mas, como eu disse, esse é um caso de uso raro). Na maioria das vezes, convém manter as confirmações antigas no reflog, caso precise recuperar dados. Consulte Pro Git: 9.7 Git Internals - Manutenção e recuperação de dados .

8

Se você deseja manter o histórico, mostrando o commit e a reversão, use:

git revert GIT_COMMIT_HASH

digite a mensagem explicando por que você está revertendo e depois:

git push  

Quando você emitir, git logverá as mensagens de log de confirmação e reversão "incorretas".


Sim, mas o OP deixou claro que não é isso que eles querem.
Steve Bennett

7

Se você acabou de estragar seu último commit (mensagem errada, esqueceu de adicionar algumas alterações) e deseja corrigi-lo antes de enviá-lo para um repositório público, por que não usar:

git commit --amend -m "New message here"

Se você tiver feito alterações recentemente preparadas, elas serão combinadas com a última confirmação (da qual você está tentando se livrar) e a substituirão.

Obviamente, se você alterar um commit depois de enviá-lo, estará reescrevendo o histórico; portanto, se fizer isso, não deixe de entender as implicações.

Você também pode passar a opção '--no-edit' em vez de '-m' se preferir usar a mensagem do commit anterior.

Documentos: http://git-scm.com/docs/git-commit.html


2
Não é isso que o OP está pedindo.
Steve Bennett

5

Se você já enviou, localize primeiro o commit que você deseja que esteja em HEAD ($ GIT_COMMIT_HASH_HERE) e execute o seguinte:

git reset --hard $GIT_COMMIT_HASH_HERE
git push origin HEAD --force

Em cada lugar em que o repositório foi clonado, execute:

git reset --hard origin/master

5

O que eu faço normalmente quando eu comprometo e empurro (se alguém o empurra, isso resolve o problema):

git reset --hard HEAD~1

git push -f origin

espero que isso ajude


5

Eu já empurrei. Precisa retornar algumas confirmações remotamente. Já tentei muitas variações, mas apenas isso de Justin via git bush está funcionando bem para mim:

git reset --hard $GIT_COMMIT_HASH_HERE
git push origin HEAD --force

4

Redefinir na filial local

git reset --hard HEAD~<Number of commit> So git reset --hard HEAD~3

Forçar envio à origem

git push -f origin

3

Faça backup do seu código na pasta temp. O comando a seguir será redefinido como o servidor.

git reset --hard HEAD
git clean -f
git pull

Se você deseja manter suas alterações e remover confirmações recentes

git reset --soft HEAD^
git pull


2

excluir confirmação local

Como você pode ver na imagem acima, eu quero excluir a reversão "test change 2" commit (SHA1 ID: 015b5220c50e3dfbb1063f23789d92ae1d3481a2 (você pode obter o SHA1 ID usando o gitkcomando git bash)).

Para que eu possa usar (todos os comandos abaixo funcionam apenas em local. Você precisa pressionar após excluir):

  1. git reset --hard 515b5220c50e3dfbb1063f23789d92ae1d3481a2// faz backup de você para essa confirmação (o ID SHA1 da alteração de teste 4 é 515b5220c50e3dfbb1063f23789d92ae1d3481a2 )
  2. git reset --hard HEAD~1 // faz backup de você antes de um commit.
  3. git reset --hard HEAD^ // Para remover o último commit do git

depois de excluir:

depois de excluir commit


2

git reset --hard HEAD~1
Você estará agora na cabeça anterior. Puxe o galho. Empurre novo código. A confirmação será removida do git


A menos que você já tenha enviado as alterações. Nesse caso, a reinicialização completa não limpará o controle remoto. Nesse caso, rebase é a boa opção
c0der512 03/03

1

git reset --hard

origem do push do git HEAD --force

Se um ou mais dos commits forem marcados, exclua as tags primeiro. Caso contrário, o commit marcado não será removido.


0

use git revert https://git-scm.com/docs/git-revert . Ele reverterá todo o código e você poderá fazer o próximo commit.Then head irá apontar para o último commit. confirmações revertidas nunca são excluídas, mas isso não afetará sua última confirmação.


0

No meu caso, meu código mágico para esse objetivo é este:

git reset --hard @{u}

Teste e me diga. Eu tentei alguns diferentes, mas este foi o único que me ajudou.

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.