Come rimuovo la vecchia cronologia da un repository git?

Temo di non riuscire a trovare nulla di simile a questo particolare scenario.

Ho un repository git con un sacco di storia: oltre 500 filiali, oltre 500 tag, che risalgono a metà 2007. Contiene ~ 19.500 commit. Vorremmo rimuovere tutta la cronologia prima del 1 gennaio 2010, per renderla più piccola e più facile da gestire (manterremo una copia completa della cronologia in un archivio).

Conosco il commit che voglio diventare la radice del nuovo repository. Tuttavia, non riesco a capire il giusto mojo git per troncare il repository per iniziare con quel commit. Sto indovinando qualche variante di

git filter-branch 

sarebbe necessario coinvolgere gli innesti; potrebbe anche essere necessario trattare ciascuno dei 200+ rami che vogliamo tenere separatamente e poi applicare nuovamente il repo (qualcosa che so come fare).

Qualcuno ha mai fatto qualcosa del genere? Ho git 1.7.2.3 se questo è importante.

Basta creare un trapianto del genitore del nuovo commit di root su nessun genitore (o su un commit vuoto, ad es. Il vero commit di root del repository). Ad esempio, echo "" > .git/info/grafts

Dopo aver creato l’innesto, ha effetto subito; dovresti essere in grado di guardare il git log e vedere che i vecchi commit indesiderati sono andati via:

 $ echo 4a46bc886318679d8b15e05aea40b83ff6c3bd47 > .git/info/grafts $ git log --decorate | tail --lines=11 commit cb3da2d4d8c3378919844b29e815bfd5fdc0210c Author: Your Name  Date: Fri May 24 14:04:10 2013 +0200 Another message commit 4a46bc886318679d8b15e05aea40b83ff6c3bd47 (grafted) Author: Your Name  Date: Thu May 23 22:27:48 2013 +0200 Some message 

Se tutto sembra come previsto, puoi semplicemente creare un semplice git filter-branch -- --all per renderlo permanente.

ATTENZIONE: dopo aver fatto il passo filtro-ramo , tutti gli ID commit saranno cambiati, quindi chiunque usi il vecchio repository non deve mai unirsi a nessuno che usa il nuovo repository.

Forse è troppo tardi per pubblicare una risposta, ma poiché questa pagina è il primo risultato di Google, potrebbe comunque essere utile.

Se vuoi liberare spazio nel tuo repository git, ma non vuoi ribuild tutti i tuoi commit (rebase o graft), ed essere ancora in grado di spingere / tirare / unire da persone che hanno il repository completo, puoi usare il git clone clone superficiale ( parametro di profondità ).

 ; Clone the original repo into limitedRepo git clone file:///path_to/originalRepo limitedRepo --depth=10 ; Remove the original repo, to free up some space rm -rf originalRepo cd limitedRepo git remote rm origin 

Potresti riuscire a ridurre il tuo repository esistente seguendo questi passaggi:

 ; Shallow to last 5 commits git rev-parse HEAD~5 > .git/shallow ; Manually remove all other branches, tags and remotes that refers to old commits ; Prune unreachable objects git fsck --unreachable ; Will show you the list of what will be deleted git gc --prune=now ; Will actually delete your data 

Ps: versioni precedenti di git non supportavano clone / push / pull da / a repository poco profondi.

Questo metodo è facile da capire e funziona bene. L’argomento dello script ( $1 ) è un riferimento (tag, hash, …) al commit a partire dal quale si desidera mantenere la cronologia.

 #!/bin/bash git checkout --orphan temp $1 # create a new branch without parent history git commit -m "Truncated history" # create a first commit on this branch git rebase --onto temp $1 master # now rebase the part of master branch that we want to keep onto this branch git branch -D temp # delete the temp branch # The following 2 commands are optional - they keep your git repo in good shape. git prune --progress # delete all the objects w/o references git gc --aggressive # aggressively collect garbage; may take a lot of time on large repos 

NOTA che i vecchi tag rimarranno ancora presenti; quindi potrebbe essere necessario rimuoverli manualmente

osservazione: so che è quasi la stessa di @yoyodin, ma qui ci sono alcuni comandi e informazioni extra importanti. Ho provato a modificare la risposta, ma dato che è una modifica sostanziale alla risposta di @yoyodin, la mia modifica è stata rifiutata, quindi ecco le informazioni!

Prova questo metodo Come troncare la cronologia git :

 #!/bin/bash git checkout --orphan temp $1 git commit -m "Truncated history" git rebase --onto temp $1 master git branch -D temp 

Qui $1 è SHA-1 del commit che si desidera mantenere e lo script creerà un nuovo ramo che contiene tutti i commit tra $1 e master e tutta la cronologia più vecchia viene eliminata. Nota che questo semplice script presuppone che tu non abbia un ramo esistente chiamato temp . Si noti inoltre che questo script non cancella i dati git per la cronologia precedente. Esegui git gc --prune=all && git repack -a -f -F -d dopo aver verificato che vuoi veramente perdere tutta la cronologia. Potresti anche aver bisogno di rebase --preserve-merges ma rebase --preserve-merges presente che l’implementazione git di quella funzione non è perfetta. Ispeziona i risultati manualmente se lo usi.

In alternativa alla riscrittura della cronologia, considera l’utilizzo di git replace come in questo articolo del libro Pro Git . L’esempio discusso riguarda la sostituzione di un commit padre per simulare l’inizio di un albero, mantenendo comunque la cronologia completa come ramo separato per la custodia.

Se si desidera mantenere il repository upstream con la cronologia completa , ma i checkout più piccoli locali, eseguire un clone poco profondo con git clone --depth=1 [repo] .

Dopo aver premuto un commit, puoi farlo

  1. git fetch --depth=1 per git fetch --depth=1 i vecchi commit. Ciò rende i vecchi commit e i loro oggetti irraggiungibili.
  2. git reflog expire --expire-unreachable=now --all . Per far scadere tutti i vecchi commit e i loro oggetti
  3. git gc --aggressive --prune=all per rimuovere i vecchi oggetti

Vedi anche Come rimuovere la cronologia git locale dopo un commit? .

Nota che non puoi spingere questo repository “superficiale” da qualche altra parte: “aggiornamento superficiale non consentito”. Vedi Remote Respinto (aggiornamento superficiale non consentito) dopo aver cambiato l’URL remoto Git . Se vuoi farlo, devi continuare con l’innesto.

Avevo bisogno di leggere diverse risposte e qualche altra informazione per capire cosa stavo facendo.

1. Ignora tutto più vecchio di un certo commit

Il file .git/info/grafts può definire i genitori falsi per un commit. Una riga con solo un ID commit, dice che il commit non ha un genitore. Se volessimo dire che ci interessiamo solo degli ultimi 2000 commit, possiamo digitare:

 git rev-parse HEAD~2000 > .git/info/grafts 

git rev-parse ci fornisce l’id di commit del 2000esimo genitore del commit corrente. Il comando sopra sovrascriverà il file di grafts se presente. Controlla se è lì prima.

2. Riscrivi la cronologia Git (opzionale)

Se vuoi far diventare questo genitore falso innato uno vero, allora esegui:

 git filter-branch -- --all 

Cambierà tutti gli ID di commit. Ogni copia di questo repository deve essere aggiornata con forza.

3. Pulire lo spazio sul disco

Non ho fatto il passaggio 3. Volevo che la mia copia rimanesse compatibile con l’upstream. Volevo solo risparmiare spazio su disco. Per dimenticare tutti i vecchi commit:

 git prune git gc 

Alternativa: copie superficiali

Se hai una copia superficiale di un altro repository e vuoi solo risparmiare spazio su disco, puoi aggiornare .git/shallow . Ma fai attenzione che nulla indichi un commit di prima. Quindi potresti eseguire qualcosa del genere:

 git fetch --prune git rev-parse HEAD~2000 > .git/shallow git prune git gc 

L’entrata in lavori superficiali come un innesto. Ma fai attenzione a non usare innesti e superficiali allo stesso tempo. Almeno, non hanno le stesse voci in là, fallirà.

Se sono ancora presenti riferimenti vecchi (tag, diramazioni, testine remote) che puntano a commit più vecchi, non verranno ripuliti e non si risparmia più spazio su disco.

Quando rebase o push to head / master, potrebbe essersi verificato questo errore

 remote: GitLab: You are not allowed to access some of the refs! To git@giturl:main/xyz.git ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'git@giturl:main/xyz.git' 

Per risolvere questo problema in git dashboard, rimuovere il ramo principale da “Rami protetti”

inserisci la descrizione dell'immagine qui

allora puoi eseguire questo comando

 git push -f origin master 

o

 git rebase --onto temp $1 master 

puoi cancellare la directory, i file e anche l’intera cronologia relativa alla directory o al file utilizzando il jar di cui sopra [scaricalo] e i comandi

file bfg.jar: https://rtyley.github.io/bfg-repo-cleaner/

git clone –bare repo-url cd repo_dir java -jar bfg.jar –delete-folders nome_cella git reflog expire –expire = now –all && git gc –prune = now –aggressive git push –mirror repo_url

  1. rimuovere git data, rm .git
  2. git init
  3. aggiungi un git remoto
  4. forza di spinta