Come schiacciare tutti i commit di git in uno?

Come si schiaccia l’intero repository fino al primo commit?

Posso rebase al primo commit, ma questo mi lascerebbe con 2 commit. C’è un modo per fare riferimento al commit prima del primo?

    Forse il modo più semplice è semplicemente creare un nuovo repository con lo stato corrente della copia di lavoro. Se si desidera mantenere tutti i messaggi di commit, è ansible prima eseguire git log > original.log e quindi modificare quello per il messaggio di commit iniziale nel nuovo repository:

     rm -rf .git git init git add . git commit 

    o

     git log > original.log # edit original.log as desired rm -rf .git git init git add . git commit -F original.log 

    Nelle versioni recenti di git, puoi usare git rebase --root -i .

    Per ogni commit tranne il primo, cambia il pick in squash .

    Aggiornare

    Ho fatto un alias git squash-all .
    Esempio di utilizzo : git squash-all "a brand new start" .

     [alias] squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f" 

    Avvertenza : ricordarsi di fornire un commento, altrimenti verrà utilizzato il messaggio di commit predefinito “Un nuovo inizio”.

    Oppure puoi creare l’alias con il seguente comando:

     git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f' 

    Una fodera

     git reset $(git commit-tree HEAD^{tree} -m "A new start") 

    Nota : qui ” A new start ” è solo un esempio, sentiti libero di usare la tua lingua.

    TL; DR

    Non c’è bisogno di schiacciare, usare git commit-tree per creare un commit orfano e andare con esso.

    Spiegare

    1. crea un singolo commit tramite git commit-tree

      Che cosa è git commit-tree HEAD^{tree} -m "A new start" è:

      Crea un nuovo object commit basato sull’object tree fornito ed emette il nuovo id object commit su stdout. Il messaggio di registro viene letto dall’input standard, a meno che non vengano fornite le opzioni -m o -F.

      L’espressione HEAD^{tree} indica l’object ad albero corrispondente a HEAD , ossia la punta del ramo corrente. vedi Tree-Objects e Commit-Objects .

    2. resettare il ramo corrente al nuovo commit

      Quindi git reset semplicemente resetta il ramo corrente all’object commit appena creato.

    In questo modo non viene toccato nulla nello spazio di lavoro, né è necessario rebase / squash, il che lo rende molto veloce. E il tempo necessario è irrilevante per la dimensione del repository o la profondità della cronologia.

    Variation: New Repo da un modello di progetto

    Questo è utile per creare il “commit iniziale” in un nuovo progetto usando un altro repository come template / archetype / seed / skeleton. Per esempio:

     cd my-new-project git init git fetch --depth=1 -n https://github.com/toolbear/panda.git git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit") 

    Ciò evita di aggiungere il repository del modello come remoto ( origin o altro) e comprime la cronologia del repository del modello nel commit iniziale.

    Se tutto quello che vuoi fare è schiacciare tutti i tuoi commit fino al commit di root, poi while

     git rebase --interactive --root 

    può funzionare, non è pratico per un gran numero di commit (ad esempio, centinaia di commit), perché l’operazione rebase verrà probabilmente eseguita molto lentamente per generare l’elenco di commit dell’editor di rebase interattivo, oltre a eseguire lo stesso rebase.

    Ecco due soluzioni più rapide ed efficienti quando stai schiacciando un gran numero di commit:

    Soluzione alternativa n. 1: rami orfani

    Puoi semplicemente creare un nuovo ramo orfano sulla punta (cioè il commit più recente) del tuo ramo corrente. Questo ramo orfano costituisce il commit iniziale della radice di un albero della cronologia del commit completamente nuovo e separato, che equivale in effetti allo schiacciamento di tutti i tuoi commit:

     git checkout --orphan new-master master git commit -m "Enter commit message for your new initial commit" # Overwrite the old master branch reference with the new one git branch -M new-master master 

    Documentazione:

    • git-checkout (1) Pagina manuale .

    Soluzione alternativa n. 2: ripristino graduale

    Un’altra soluzione efficiente consiste semplicemente nell’utilizzare un reset misto o soft per il commit :

     git branch beforeReset git reset --soft  git commit --amend # Verify that the new amended root is no different # from the previous branch state git diff beforeReset 

    Documentazione:

    • git-reset (1) Pagina manuale .
     echo "message" | git commit-tree HEAD^{tree} 

    Questo creerà un commit orfano con l’albero di HEAD e produrrà il suo nome (SHA-1) su stdout. Quindi resetta il tuo ramo lì.

     git reset SHA-1 

    Ecco come ho finito per farlo, nel caso in cui funzioni per qualcun altro:

    Ricorda che c’è sempre il rischio nel fare cose come questa, e non è mai una ctriggers idea creare un ramo di salvataggio prima di iniziare.

    Inizia con la registrazione

     git log --oneline 

    Scorri fino al primo commit, copia SHA

     git reset --soft < #sha#> 

    Sostituisci < #sha#> w / SHA copiato dal registro

     git status 

    Assicurati che tutto sia verde, altrimenti esegui git add -A

     git commit --amend 

    Modificare tutte le modifiche correnti al primo commit corrente

    Ora forza spingi questo ramo e questo sovrascriverà quello che c’è.

    Il modo più semplice è utilizzare il comando ‘plumbing’ update-ref per eliminare il ramo corrente.

    Non puoi usare git branch -D perché ha una valvola di sicurezza che ti impedisce di eliminare il ramo corrente.

    Questo ti riporta nello stato ‘commit iniziale’ in cui puoi iniziare con un nuovo commit iniziale.

     git update-ref -d refs/heads/master git commit -m "New initial commit" 

    Ho letto qualcosa sull’uso degli innesti, ma non l’ho mai studiato molto.

    Ad ogni modo, puoi schiacciare manualmente quegli ultimi 2 commit con qualcosa del genere:

     git reset HEAD~1 git add -A git commit --amend 

    Prima di tutto, schiaccia tutti i tuoi commit in un singolo commit usando git rebase --interactive . Ora sei rimasto con due commit da schiacciare. Per fare ciò, leggi uno di

    • Come combino i primi due commit di un repository Git?
    • git: come schiacciare i primi due commit?

    Per schiacciare usando gli innesti

    Aggiungi un file. .git/info/grafts , metti lì l’hash del commit che vuoi diventare la tua radice

    git log inizierà ora da quel commit

    Per renderlo ‘reale’ esegui git filter-branch

    “La soluzione alternativa n. 1: i rami orfani” mi aiuta.

    “git rebase –interactive –root” bloccato sul conflitto di file gitignored.

    Questa risposta migliora di un paio sopra (si prega di votarli), partendo dal presupposto che oltre a creare un commit (no-parents no-history), si desidera anche conservare tutti i dati di commit di quel commit:

    • Autore (nome e indirizzo email)
    • Data d’autore
    • Committente (nome e indirizzo email)
    • Data impegnata
    • Invia messaggio di log

    Ovviamente il commit-SHA del nuovo / singolo commit cambierà, poiché rappresenta una nuova (non-) cronologia, diventando un genitore / root-commit.

    Questo può essere fatto leggendo git log e impostando alcune variabili per git commit-tree . Supponendo che si voglia creare un singolo commit dal master in un nuovo ramo one-commit , mantenendo i dati di commit sopra:

     git checkout -b one-commit master ## create new branch to reset git reset --hard \ $(eval "$(git log master -n1 --format='\ COMMIT_MESSAGE="%B" \ GIT_AUTHOR_NAME="%an" \ GIT_AUTHOR_EMAIL="%ae" \ GIT_AUTHOR_DATE="%ad" \ GIT_COMMITTER_NAME="%cn" \ GIT_COMMITTER_EMAIL="%ce" \ GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <  

    Di solito lo faccio in questo modo:

    • Assicurarsi che tutto sia stato eseguito e annotare l’ultimo ID commit nel caso in cui qualcosa vada storto o creare un ramo separato come backup

    • Esegui git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD` per reimpostare la tua testa sul primo commit, ma lascia il tuo indice invariato. Tutte le modifiche dal primo commit ora appariranno pronte per essere confermate.

    • Esegui git commit --amend -m "initial commit" per modificare il commit al primo commit e modificare il messaggio di commit, oppure se vuoi mantenere il messaggio di commit esistente, puoi eseguire git commit --amend --no-edit

    • Esegui git push -f per forzare le modifiche

    creare un backup

     git branch backup 

    ripristina il commit specificato

     git reset --soft  

    aggiungi tutti i file alla stadiazione

     git add . 

    commit senza aggiornare il messaggio

     git commit --amend --no-edit 

    spingere il nuovo ramo con i commit schiacciati per il repo

     git push -f 

    In una riga di 6 parole

     git checkout --orphan new_root_branch && git commit