Domanda

Supponiamo che la tua cronologia git sia simile a questa:

1 2 3 4 5

1–5 sono revisioni separate.Devi rimuoverne 3 mantenendo comunque 1, 2, 4 e 5.Come si può fare?

Esiste un metodo efficace quando ci sono centinaia di revisioni dopo quella da eliminare?

È stato utile?

Soluzione

Per combinare la revisione 3 e 4 in un'unica revisione, puoi utilizzare git rebase.Se desideri rimuovere le modifiche nella revisione 3, devi utilizzare il comando modifica nella modalità rebase interattiva.Se vuoi combinare le modifiche in un'unica revisione, usa squash.

Ho utilizzato con successo questa tecnica di squash, ma non ho mai avuto bisogno di rimuovere una revisione prima.Si spera che la documentazione di git-rebase sotto "Suddivisione dei commit" dovrebbe darti un'idea sufficiente per capirlo.(O qualcun altro potrebbe saperlo).

Dal documentazione di Git:

Inizia con il commit più vecchio che desideri mantenere così com'è:

git rebase -i <after-this-commit>

Un editor verrà avviato con tutti i commit nel tuo ramo corrente (ignorando i commit di unione), che vengono dopo il commit specificato.Puoi riordinare i commit in questo elenco a tuo piacimento e puoi rimuoverli.L'elenco è più o meno così:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

Le descrizioni su una riga sono puramente per il tuo piacere;git-rebase non li esaminerà ma i nomi dei commit ("deadbee" e "fa1afe1" in questo esempio), quindi non eliminare o modificare i nomi.

Sostituendo il comando "pick" con il comando "edit", puoi dire a git-rebase di fermarsi dopo aver applicato quel commit, in modo da poter modificare i file e/o il messaggio di commit, modificare il commit e continuare il rebasing.

Se vuoi unire due o più commit in uno solo, sostituisci il comando "pick" con "squash" per il secondo commit e quelli successivi.Se i commit avevano autori diversi, attribuirà il commit schiacciato all'autore del primo commit.

Altri suggerimenti

Ecco un modo per rimuovere in modo non interattivo un file specifico <commit-id>, conoscendo solo il <commit-id> vorresti rimuovere:

git rebase --onto <commit-id>^ <commit-id> HEAD

Per questo commento (e ho verificato che sia vero), la risposta di rado è molto vicina ma lascia git in uno stato di testa distaccata.Invece rimuovi HEAD e usalo per rimuoverlo <commit-id> dalla filiale in cui ti trovi:

git rebase --onto <commit-id>^ <commit-id>

Come notato prima git-rebase(1) È tuo amico.Supponendo che i commit siano nel tuo master ramo, faresti:

git rebase --onto master~3 master~2 master

Prima:

1---2---3---4---5  master

Dopo:

1---2---4'---5' master

Da git-rebase(1):

Una serie di commit potrebbe anche essere rimossa con Rebase.Se abbiamo la seguente situazione:

E---F---G---H---I---J  topicA

poi il comando

git rebase --onto topicA~5 topicA~3 topicA

comporterebbe la rimozione di commissioni f e g:

E---H'---I'---J'  topicA

Ciò è utile se F e G fossero in qualche modo imperfetti o non dovrebbero far parte di Topica.Si noti che l'argomento a -onto e il parametro può essere qualsiasi commit valido.

Se tutto ciò che vuoi fare è rimuovere le modifiche apportate nella revisione 3, potresti voler utilizzare git revert.

Git revert crea semplicemente una nuova revisione con modifiche che annullano tutte le modifiche nella revisione che stai ripristinando.

Ciò significa che conservi le informazioni sia sul commit indesiderato, sia sul commit che rimuove tali modifiche.

Questo è probabilmente molto più amichevole se è possibile che qualcuno abbia estratto dal tuo repository nel frattempo, dal momento che il ripristino è fondamentalmente solo un commit standard.

Tutte le risposte finora non risolvono il problema finale:

Esiste un metodo efficiente in cui ci sono centinaia di revisioni dopo che quella da eliminare?

I passaggi seguono, ma per riferimento, assumiamo la seguente cronologia:

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]

C:commit subito dopo il commit da rimuovere (pulito)

R:Il commit da rimuovere

B:commit appena precedente il commit da rimuovere (base)

A causa del vincolo "centinaia di revisioni", presumo le seguenti precondizioni:

  1. c'è qualche impegno imbarazzante che vorresti non fosse mai esistito
  2. ci sono ZERO commit successivi che in realtà dipendono da quel commit imbarazzante (zero conflitti al ripristino)
  3. non ti interessa essere elencato come il "Committer" tra le centinaia di commit intervenuti ("Autore" verrà preservato)
  4. non hai mai condiviso il repository
    • oppure hai abbastanza influenza su tutte le persone che hanno mai clonato la storia con quel commit per convincerli a usare la tua nuova storia
    • E tu non importa Di riscrivere la storia

Si tratta di un insieme di vincoli piuttosto restrittivo, ma esiste una risposta interessante che funziona effettivamente in questo caso limite.

Ecco i passaggi:

  1. git branch base B
  2. git branch remove-me R
  3. git branch save
  4. git rebase --preserve-merges --onto base remove-me

Se davvero non ci sono conflitti, allora si dovrebbe procedere senza ulteriori interruzioni.Se ci sono conflitti, puoi risolverli e rebase --continue o decidere di convivere semplicemente con l'imbarazzo e rebase --abort.

Ora dovresti essere attivo master che non ha più commit R dentro.IL save la diramazione punta al punto in cui eri prima, nel caso in cui desideri riconciliarti.

Sta a te decidere come organizzare il trasferimento di tutti gli altri nella tua nuova cronologia.Avrai bisogno di conoscere stash, reset --hard, E cherry-pick.E puoi eliminare il file base, remove-me, E save rami

Quindi ecco lo scenario che ho dovuto affrontare e come l'ho risolto.

[branch-a]

[Hundreds of commits] -> [R] -> [I]

Qui R è il commit di cui avevo bisogno per essere rimosso, e I è un singolo commit che viene dopo R

Ho effettuato un ripristino del commit e li ho messi insieme

git revert [commit id of R]
git rebase -i HEAD~3

Durante il rebase interattivo schiaccia gli ultimi 2 commit.

Anch'io sono finito in una situazione simile.Utilizza il rebase interattivo utilizzando il comando seguente e mentre selezioni, rilascia il terzo commit.

git rebase -i remote/branch

Le risposte di rado e kareem non fanno nulla per me (viene visualizzato solo il messaggio "Il ramo corrente è aggiornato").Forse ciò accade perché il simbolo '^' non funziona nella console Windows.Tuttavia, secondo Questo commento, la sostituzione di '^' con '~1' risolve il problema.

git rebase --onto <commit-id>^ <commit-id>

Per rimuovere la vecchia cronologia dei commit dal repository git:

Prima esegui sotto cmd

rm -rf .git

-- ricrea il repository dalla corrente

git init                                                                           
git add .                                                  
git commit -m "first commit"

-- push sui repository remoti github

git remote add origin git@github.com<your git mail>   
git push -u --force origin master
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top