Combina i primi due commit di un repository Git?


197

Supponiamo di avere una cronologia contenente i tre commit A, B e C :

A-B-C

Vorrei combinare i due commit A e B con un commit AB :

AB-C

Provai

git rebase -i A

che apre il mio editor con i seguenti contenuti:

pick e97a17b B
pick asd314f C

Lo cambio a

squash e97a17b B
pick asd314f C

Quindi Git 1.6.0.4 dice:

Cannot 'squash' without a previous commit

C'è un modo o è semplicemente impossibile?



Risposte:


169

Utilizzare a git rebase -i --root partire dalla versione 1.7.12 di Git .

Nel file di rebase interattivo, modifica la seconda riga di commit B per schiacciarla e lascia le altre righe a scelta :

pick f4202da A
squash bea708e B
pick a8c6abc C

Questo combinerà i due commit A e B con un commit AB .

Trovato in questa risposta .


126

Hai provato:

git rebase -i A

È possibile iniziare così se si continua con editpiuttosto che squash:

edit e97a17b B
pick asd314f C

quindi corri

git reset --soft HEAD^
git commit --amend
git rebase --continue

Fatto.


4
Se lo stai facendo per correggere silenziosamente una sintesi di github, dovrai aggiungere -m "iniziale" al commit. ;-)
Bruno Bronosky,

1
git rebase --abortricominciare da capo e farlo nel modo giusto (senza schiacciare il primo commit nell'editor)
oma

66

Aera il commit iniziale, ma ora vuoi Bessere il commit iniziale. I commit git sono alberi interi, non diff anche se sono normalmente descritti e visualizzati in termini di diff che introducono.

Questa ricetta funziona anche se ci sono più commit tra A e B e B e C.

# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout <sha1_for_B>

# reset the branch pointer to the initial commit,
# but leaving the index and working tree intact.
git reset --soft <sha1_for_A>

# amend the initial tree using the tree from 'B'
git commit --amend

# temporarily tag this new initial commit
# (or you could remember the new commit sha1 manually)
git tag tmp

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after B onto the new initial commit
git rebase --onto tmp <sha1_for_B>

# remove the temporary tag
git tag -d tmp

1
questo innesca un enorme rebase interattivo quando faccio ilgit rebase --onto tmp <sha1_for_B>
Alex

Considerando che avevo un nuovo repository con solo due commit (che volevo inserire in uno), questo ha funzionato perfettamente per me. Grazie @CB Bailey
RominRonin il

10

Nel caso di rebase interattivo, devi farlo prima di A in modo che l'elenco sia:

pick A
pick B
pick C

diventare:

pick A
squash B
pick C

Se A è il commit iniziale, devi avere un commit iniziale diverso prima che A. Git pensi alle differenze, funzionerà sulla differenza tra (A e B) e (B e C). Quindi la zucca non funziona nel tuo esempio.


9

Nel caso in cui tu abbia centinaia o migliaia di commit, usando la risposta di kostmo di

git rebase -i --root

può essere poco pratico e lento, solo a causa dell'elevato numero di commit che lo script rebase deve elaborare due volte , una volta per generare l'elenco dell'editor di rebase interattivo (dove si seleziona quale azione intraprendere per ciascun commit) e una volta per eseguire effettivamente il nuova applicazione di commit.

Ecco una soluzione alternativa che eviterà il costo in termini di tempo per generare l'elenco dell'editor di rebase interattivo, in primo luogo non utilizzando un rebase interattivo . In questo modo, è simile alla soluzione di Charles Bailey . È sufficiente creare un ramo orfano dal secondo commit, quindi riepilogare tutti i commit discendenti su di esso:

git checkout --orphan orphan <second-commit-sha>
git commit -m "Enter a commit message for the new root commit"
git rebase --onto orphan <second-commit-sha> master

Documentazione



0

Comando git per squadra: git rebase -i HEAD ~ [numero di commit]

Diciamo che hai sotto la cronologia di commit di git:


pick 5152061 feat: Aggiunto il supporto per il salvataggio dell'immagine. (A)
scegli 39c5a04 Correzione: correzioni di errori. (B)
scegli correzione 839c6b3: conflitto risolto. (C)

Ora vuoi schiacciare A e B su AB, esegui i passaggi seguenti:


pick 5152061 feat: Aggiunto il supporto per il salvataggio dell'immagine. (A)
s 39c5a04 Correzione: correzioni di errori. (B)
scegli correzione 839c6b3: conflitto risolto. (C)

Nota: per il commit di squash possiamo usare squash o s. Il risultato finale sarà:
scegli 5152061 feat: Aggiunto il supporto per il salvataggio dell'immagine. (AB)
scegli correzione 839c6b3: conflitto risolto. (C)


-1

Devi eseguire un po 'di magia da riga di comando.

git checkout -b a A
git checkout B <files>
git commit --amend
git checkout master
git rebase a

Ciò dovrebbe lasciarti con un ramo che ha AB e C come commit.


Poiché il vecchio e il nuovo commit iniziale non hanno antenati comuni, potresti avere alcuni conflitti inutili mentre git cerca di applicare l'intera storia del master su un, anche se hanno un albero in comune. Usando l'opzione --onto per git rebase puoi dire a git il posto giusto per iniziare l'applicazione.
CB Bailey,
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.