Come rimuovere permanentemente alcuni commit dalla filiale remota


490

So che è una riscrittura della storia che è male yada yada.

Ma come rimuovere permanentemente alcuni commit dalla filiale remota?


96
Sì, è davvero brutto yada yada, ma per qualche ragione ho bisogno di favorirlo.
James Morris,

44
So che è stupido, ma a volte succede qualcosa di simile - come testare gli accessi e usare password in chiaro nel tuo codice, che sono vere credenziali di accesso. E whoops ...
dal

6
credenziali di accesso reali. Sì, mi viene in mente alcuni whoopos
Hello Universe,


2
Sono così stanco di questo accento accademico su quanto sia pericoloso e su come non dovrebbe mai essere fatto yada yada. Ci sono momenti in cui è di gran lunga molto meglio rimuovere cose dalla storia di Git e affrontare i conflitti / rotture di altri sviluppatori. È davvero così semplice. Le persone che lo ignorano probabilmente non hanno mai lavorato al di fuori di un ambiente scolastico.
schiaccia il

Risposte:


369

Sei il git reset --hardtuo ramo locale per rimuovere le modifiche dall'albero e dall'indice di lavoro e il git push --forcetuo ramo locale rivisto sul telecomando. ( altra soluzione qui , che consiste nell'eliminare il ramo remoto e reinserirlo)

Questa risposta SO illustra il pericolo di tale comando, soprattutto se le persone dipendono dalla cronologia remota per i propri repository locali.
Devi essere pronto a segnalare alle persone la sezione RECUPERARE DA REVISIONE UPSTREAM della git rebasepagina man


Con Git 2.23 (agosto 2019, nove anni dopo), useresti il ​​nuovo comando git switch.
Cioè: (sostituiscigit switch -C mybranch origin/mybranch~n
n con il numero di commit da rimuovere)

Ciò ripristinerà l'indice e l'albero di lavoro, come git reset --hardfarebbe.


Strano. Mi sento come se ci avessi già provato. Insieme ad alcuni rebasing - funziona come un fascino. Grazie.
Arnis Lapsa,

7
@Arnis: perfetto allora;) push --forcevia
VonC

Ho usato BFG Repo-Cleaner per sbarazzarmi di alcuni dati sensibili, che mi hanno lasciato con un ramo "senza nome" con il file originale su di esso, dopo aver ripristinato l'ultimo commit desiderato e aver spinto forte l'origine, tutto è andato bene (:
Rodrirokr

Nota che l'URL del commit è ancora attivo (almeno per qualche tempo), quindi se qualcuno ha l'URL del commit (lo hai dato a dio sa perché), saranno in grado di accedere al codice.
Mosh Feu

1
@MoshFeu True: git gcnon sempre viene eseguito abbastanza spesso sul lato remoto. Ad esempio su GitHub: twitter.com/githubhelp/status/387926738161774592?lang=es
VonC

248

Basta notare di usare il last_working_commit_id, quando si ripristina un commit non funzionante

git reset --hard <last_working_commit_id>

Quindi non dobbiamo ripristinare commit_idciò che non vogliamo.

Quindi certo, dobbiamo spingere al ramo remoto:

git push --force

10
Risposta perfetta, elegante, più semplice. Sono appena tornato all'ultimo commit di stabke di cui avevo bisogno sia in remoto che localmente
lauWM il

2
Questo mi ha fatto perdere anche le mie modifiche locali. Non me lo aspettavo. Ma io, meglio di impegnare la tua password personale per il repository di lavoro.
Airwavezx,

3
puoi salvare le tue modifiche locali con git stash .... crea alcune cose .... e git stash pop (le tue modifiche locali sono tornate)
MonTea

Questo mi dà l'errore "remote: error:
dening refs

@Airwavezx è quello che git reset --harddovrebbe fare.
Luca

146

Importante: assicurati di specificare quali rami su "git push -f" o potresti modificare inavvertitamente altri rami! [*]

Ci sono tre opzioni mostrate in questo tutorial . In caso di interruzione del collegamento, lascerò qui i passaggi principali.

  1. Ripristina il commit completo
  2. Elimina l'ultimo commit
  3. Elimina il commit da un elenco

1 Ripristina il commit completo

git revert dd61ab23

2 Elimina l'ultimo commit

git push <<remote>> +dd61ab23^:<<BRANCH_NAME_HERE>>

oppure, se il ramo è disponibile localmente

git reset HEAD^ --hard
git push <<remote>> -f

dove + dd61 ... è il tuo hash di commit e git interpreta x ^ come il genitore di x, e + come una spinta forzata non anticipata.

3 Elimina il commit da un elenco

git rebase -i dd61ab23^

Questo si aprirà e l'editor mostrerà un elenco di tutti i commit. Elimina quello a cui vuoi sbarazzarti. Termina il rebase e spingi la forza verso il repo.

git rebase --continue
git push <remote_repo> <remote_branch> -f

5
Assicurati di specificare quali rami su "git push <remote_repo> <remote_branch> -f" o potresti modificare inavvertitamente altri rami!
Nigel Sheridan-Smith,

Solo i passaggi 1 e 2 hanno svolto il lavoro e risposto alla domanda originale. (Non eseguire il passaggio 3)
Saad Benbouzid,

Queste sono opzioni per diversi scenari, non passi da compiere. Nel mio caso, il rebase interattivo (Opzione 3) ha fatto quello che stavo cercando.
Steve Blackwell,

Ho dovuto fare il passaggio 3 però. Perché non dovresti eseguire questo @Saad? Fortunatamente il mio <<remote>> era semplicemente l'origine predefinita e <remote_branch> il 'maestro' predefinito
Bart

30

Se si desidera eliminare, ad esempio, gli ultimi 3commit, eseguire il comando seguente per rimuovere le modifiche dal file system (albero di lavoro) e commettere la cronologia (indice) sul ramo locale:

git reset --hard HEAD~3

Quindi eseguire il comando seguente (sul computer locale) per forzare il ramo remoto a riscrivere la sua cronologia:

git push --force

Congratulazioni! Tutto fatto!

Alcune note:

È possibile recuperare l'id di commit desiderato eseguendo

git log

Quindi è possibile sostituire HEAD~Ncon in <desired-commit-id>questo modo:

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

Se si desidera mantenere le modifiche sul file system e modificare solo l'indice (cronologia commit), utilizzare --softflag like git reset --soft HEAD~3. Quindi hai la possibilità di controllare le ultime modifiche e conservarle o eliminarle tutte o parte di esse. In quest'ultimo caso runnig git statusmostra i file modificati da allora <desired-commit-id>. Se usi l' --hardopzione, git statusti dirà che la tua filiale locale è esattamente la stessa di quella remota. Se non si utilizza --hard--soft, viene utilizzata la modalità predefinita --mixed. In questa modalità, git help resetdice:

Reimposta l'indice ma non l'albero di lavoro (ovvero, i file modificati vengono conservati ma non contrassegnati per il commit) e riporta ciò che non è stato aggiornato.


10

Potrebbe essere troppo tardi, ma ciò che mi ha aiutato è l'opzione "nucleare" che suona bene. Fondamentalmente usando il comandofilter-branch è possibile rimuovere i file o modificare qualcosa su un gran numero di file in tutta la cronologia di Git.

È meglio spiegato qui .


9
Non è troppo tardi Potrebbe essere utile per i vagabondi con problemi simili :)
Arnis Lapsa,

9

Semplificazione dalla risposta di pctroll, analogamente sulla base di questo post sul blog .

# look up the commit id in git log or on github, e.g. 42480f3, then do
git checkout master
git checkout your_branch
git revert 42480f3
# a text editor will open, close it with ctrl+x (editor dependent)
git push origin your_branch
# or replace origin with your remote

2
Funziona per me, grazie. E voglio eliminare definitivamente un commit (es. Contiene pwd) dalla cronologia delle filiali remote, come si fa?
Sorride il

1
Funziona anche per me, ma ho la stessa domanda di Smiles, non voglio che nessuno veda il mio impegno / venerazione nella storia .. come lo rimuovo?
Roberto Rodriguez,

4

A volte il modo più semplice per risolvere questo problema è creare un nuovo ramo dal punto in cui sai che il codice è buono. Quindi puoi lasciare da solo la cronologia del ramo errato nel caso in cui tu debba selezionare altri commit da esso in seguito. Questo assicura anche che non hai perso alcuna cronologia di commit.

Dal tuo ramo locale errante:

git log

copia l'hash di commit in cui vuoi che si trovasse il ramo ed esci dal registro git

git checkout theHashYouJustCopied
git checkout -b your_new_awesome_branch

Ora hai una nuova filiale nel modo che preferisci.

Se hai anche bisogno di mantenere un commit specifico dal ramo errato che non si trova sul tuo nuovo ramo, puoi semplicemente selezionare quel commit specifico di cui hai bisogno:

git checkout the_errant_branch
git log

Copia l'hash di commit di un commit che devi inserire nel buon ramo ed uscire dal registro git.

git checkout your_new_awesome_branch
git cherry-pick theHashYouJustCopied

Datti una pacca sulla schiena.


molto facile e chi se ne frega se hai un ramo dalle gambe morte? crea una nuova filiale e falla finita!
Andrew Fox,

Questa è una risposta davvero eccellente. Sono contento di averlo fatto invece di impegnarmi nella raccolta delle ciliegie o di manipolare il ramo remoto.
Magnilex,

0
 git reset --soft commit_id
 git stash save "message"
 git reset --hard commit_id
 git stash apply stash stash@{0}
 git push --force
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.