Come posso risolvere una sottostruttura git dopo che la forza del progetto a monte è stata inserita nel master?


13

Ho provato a usare git subtree e ho riscontrato la seguente situazione.

Ho usato git subtree per aggiungere un progetto esterno al mio repository, ho intenzionalmente conservato tutta la cronologia del progetto a monte poiché desidero poter fare riferimento alla storia del progetto e contribuire anche al progetto a monte in un secondo momento.

A quanto pare, un altro collaboratore del progetto upstream ha inserito accidentalmente un file di grandi dimensioni nel ramo principale. Per risolvere questo problema, il progetto a monte riscrisse la storia e la forza spinse sul master. Quando ho creato il mio "monorepo", ho incluso questo commit e vorrei anche rimuoverlo.

Come posso aggiornare il mio repository per riflettere la nuova cronologia della sottostruttura?

Il mio primo tentativo è stato di utilizzare il filtro-ramo per rimuovere completamente la sottostruttura e tutta la cronologia.

git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch upstream-project-dir' --prune-empty HEAD

Una volta rimossa la vecchia versione della sottostruttura, ho potuto aggiungere nuovamente la sottostruttura utilizzando il nuovo master upstream. Tuttavia, questo non ha funzionato perché per qualche motivo la cronologia del commit viene ancora visualizzata nell'output del log git.

Aggiornare

Ho scritto i passaggi per creare un esempio minimamente riproducibile.

  1. Per prima cosa crea un repository git vuoto.

    git init test-monorepo
    cd ./test-monorepo
    
  2. Crea un commit iniziale.

    echo hello world > README
    git add README
    git commit -m 'initial commit'
    
  3. Ora aggiungi una sottostruttura per un progetto esterno.

    git remote add thirdparty git@github.com:teivah/algodeck.git
    git fetch thirdparty
    git subtree add --prefix algodeck thirdparty master
    
  4. Fai alcuni commit sul monorepo

    echo dont panic >> algodeck/README.md
    git commit -a -m 'test commit'
    
  5. Ora prova a usare git filter-branch per rimuovere la sottostruttura.

    git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
    
  6. Esaminare l'output del registro git, mi aspetto di vedere solo il mio commit iniziale.

    git log
    

Hai provato a git gc --prune = ora per eliminare i vecchi commit? Ci sono alcuni riferimenti alla commit della vecchia versione?
Damiano,

1
Non l'ho ancora provato, ma non git gc --prune=noweliminerei solo i commit che non compaiono in git log?
csnate del

usando git branch -all (che suppongo tu stia usando per vedere i "vecchi" commit) dovrebbe mostrare anche i commit non correlati al tuo ramo corrente.
Damiano,

1
In realtà, stavo solo facendo git log, senza discussioni e vedo ancora i vecchi commit.
csnate,

Per favore, puoi pubblicare il tuo log git --pretty --all --graph? Giusto per capire la tua situazione
Damiano,

Risposte:


0

hai già commesso un cattivo impegno nella tua storia e devi liberartene prima di continuare

supponiamo che tu abbia ottenuto il masterdeviazione dell'ultimo commit e che non sia stato in grado di fare nient'altro (non ho davvero i tuoi rami a vista, quindi devo assumere qualcosa con cui cominciare)

puoi fare il checkout al commit precedente e spingere il tuo marker di ramo 1 passo indietro (o X passi indietro) che sarebbe comunque innocuo e poi tirare di nuovo

per esempio

git checkout master~1
git branch master -f
git checkout master
git pull
  1. git checkout master~1 per verificare il commit del genitore del master, git avverte che siamo fuori dai rami
  2. git branch master -f per forzare il checkout corrente a diventare nuovamente master, ovvero in realtà riavvolge il ramo master al suo precedente commit (o X commit precedente) e da qui non importa se a monte ha fatto una forza o no, possiamo riprendere normalmente, o anche tornare al passaggio precedente se necessario, possiamo solo tirare di nuovo il master, senza perdere nulla dall'upstream (che per noi potrebbe essere di sola lettura, non spingeremo nulla per questo)
  3. git checkout master per essere sul nostro ramo principale "riavvolto", lo stesso commit a cui stiamo facendo un passo, ma ora ci troviamo sul ramo
  4. git pullper tirare di nuovo il master (può essere con o senza --prune), se deviato a monte, torneremo in pista da qui, in caso contrario, avremo lo stesso che avevamo, se avessimo lo stesso e non si supponeva, forse noi è necessario tornare al primo passaggio sopra e riavvolgere più commit, ad es. git checkout master~5o qualsiasi altra cosa (secondo necessità)

Non credo che funzionerà congit subtree
csnate

@csnate è possibile checkout impegna precedenti da un subrepo e seguire la procedura molto simile, se si costruisce un MCVE sarebbe più facile per dirvi i comandi esatti da seguire stackoverflow.com/help/minimal-reproducible-example
arhak

Proverò a creare un repository di esempio su GitHub.
csnate

Ho creato una serie di passaggi nella domanda originale che mostra il problema.
csnate

0
  1. sul tuo repository, ripulisci la cronologia degli commit per questo telecomando:

    git fetch upstream
    
  2. se uno dei tuoi commit ha un commit che include il file di grandi dimensioni, riscrivi la cronologia in modo che questo file di grandi dimensioni non venga più indicato

    # using one or more of the following commands :
    git rebase --interactive
    git filter-branch
    ...
    

Con questi due passaggi, il file di grandi dimensioni non verrà più indicato da alcun commit nel repository.
Verrà inoltre eliminato dal disco rigido in un determinato momento, quando git esegue il suo Garbage Collector e sono stati raggiunti i ritardi di scadenza per i BLOB penzolanti.


Se hai urgente bisogno di eliminare questo file di grandi dimensioni APPENA POSSIBILE dal tuo disco rigido:

Esegui manualmente

git gc --prune=now
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.