Domanda

    

Questa domanda ha già una risposta qui:

         

Con git rebase --interactive <commit> si può schiacciare qualsiasi numero di commit insieme in una sola.

Questo è tutto grande a meno che non si desidera zucca impegna nel primo commit. Che sembra impossibile da fare.

Ci sono modi per realizzarla?


moderatamente correlati:

In una questione connessa, sono riuscito a trovare un approccio diverso alla necessità di schiacciamento contro il primo commit, che è, ben, per rendere il secondo.

Se siete interessati: git: come inserire un commit come il primo, spostando tutti gli altri

È stato utile?

Soluzione

Aggiornamento luglio 2012 ( git 1.7.12 + )

È ora possibile rebase tutti i commit fino a radice, e selezionare la seconda Y impegnarsi a essere schiacciato con il primo X.

git rebase -i --root master

pick sha1 X
squash sha1 Y
pick sha1 Z
git rebase [-i] --root $tip
     

Questo comando può ora essere utilizzato per riscrivere tutta la storia che porta da "$tip" fino alla radice commit.

commettere df5df20c1308f936ea542c86df1e9c6974168472 su GitHub da Chris Webb (arachsys) .


risposta Originale (febbraio 2009)

Credo che troverete ricette diverse per che nella questione SO " Come faccio a combinare i primi due commit di un repository git? "

Charles Bailey ci ha fornito il più risposta dettagliata , ricordandoci che un commit è un albero pieno (e non solo diff da una precedente Uniti).
E qui il vecchio commit (la "Initial commit") e il nuovo commit (risultato della spremitura) avrà nessun antenato comune.
Ciò significa che non si può "commit --amend" l'iniziale impegnarsi in uno nuovo, e poi Rebase sul nuovo primo commit la storia del primo commit precedente (un sacco di conflitti)

(Quest'ultima frase non è più vero con git rebase -i --root <aBranch> è)

Piuttosto (con A l'originale "iniziale commit", ed una successiva B impegnarsi doveva essere schiacciato in quella iniziale):

  1. tornare alla ultima impegniamo che vogliamo formare il primo commit (staccare HEAD):

    git checkout <sha1_for_B>
    
  2. Ripristina il puntatore del ramo a quella iniziale commettere, ma lasciando l'indice e albero di lavoro intatta:

    git reset --soft <sha1_for_A>
    
  3. Modificare l'albero iniziale utilizzando l'albero da 'B':

    git commit --amend
    
  4. Temporaneamente tag questo nuovo primo commit (o si potrebbe ricordare la nuova commettere SHA1 manualmente):

    git tag tmp
    
  5. Torna al ramo originale (assumere master per questo esempio):

    git checkout master
    
  6. Replay tutti i commit dopo B sul nuovo iniziale impegnano:

    git rebase --onto tmp <sha1_for_B>
    
  7. Rimuovi il tag temporanea:

    git tag -d tmp
    

In questo modo, il "rebase --onto" non introduce conflitti durante l'unione, in quanto rebases storia fatti dopo il l'ultimo commit (B) per essere schiacciato in quella iniziale (che era A) a tmp (che rappresenta la schiacciata nuova iniziale commit): banale fast-forward si fonde solo.

che funziona per "A-B", ma anche "A-...-...-...-B" (qualsiasi numero di commit può essere schiacciato in quella iniziale in questo modo)

Altri suggerimenti

Ho rielaborato la sceneggiatura di VonC di fare tutto in modo automatico e non mi chiedere nulla. Si dà due commettere SHA1s e sarà schiacciare tutto tra di loro in un unico commit chiamato "storia schiacciata":

#!/bin/sh
# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout $2

# reset the branch pointer to the initial commit (= $1),
# but leaving the index and working tree intact.
git reset --soft $1

# amend the initial tree using the tree from $2
git commit --amend -m "squashed history"

# remember the new commit sha1
TARGET=`git rev-list HEAD --max-count=1`

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

# Replay all the commits after $2 onto the new initial commit
git rebase --onto $TARGET $2

Per quello che vale, evito questo problema creando sempre un "no-op" primo commit, in cui l'unica cosa che nel repository è un .gitignore vuoto:

https://github.com/DarwinAwardWinner/ git-custom-comandi / blob / master / bin / git-myinit

In questo modo, non c'è mai stato alcun motivo di pasticciare con il primo commit.

Se si vuole semplicemente schiacciare tutti i commit in un unico iniziale commesso, basta ripristinare il repository e modificare il primo commit:

git reset hash-of-first-commit
git add -A
git commit --amend

Ripristino Git lascerà l'albero di lavoro intatto, quindi tutto è ancora lì. Quindi, basta aggiungere i file utilizzando git add comandi e modificare il primo commit con questi cambiamenti. Rispetto a rebase -i perderai la possibilità di unire i commenti git però.

Questo schiacciare secondo impegnarsi in prima:

A-B-C-... -> AB-C-...

git filter-branch --commit-filter '
    if [ "$GIT_COMMIT" = <sha1ofA> ];
    then
        skip_commit "$@";
    else
        git commit-tree "$@";
    fi
' HEAD

Commit messaggio per AB sarà preso dalla B (anche se io preferirei da A).

Ha lo stesso effetto di risposta di Uwe Kleine-König, ma funziona per i non-iniziale A pure.

schiacciando il primo e il secondo impegnarsi comporterebbe primo commit vengano riscritti. Se si dispone di più di un ramo che si basa fuori il primo commit, devi tagliare quel ramo.

Si consideri il seguente esempio:

a---b---HEAD
 \
  \
   '---d

Squashing ae b in un nuovo commit "ab" porterebbe a due alberi distinti che nella maggioranza dei casi non è desiderabile poiché git-merge e git-rebase sarà lavorare non è più tra i due rami.

ab---HEAD

a---d
Se si vuole veramente questo, si può fare

. Date un'occhiata a git-filter-branch di un potente (e pericolosa) strumento per la storia riscrittura.

È possibile utilizzare git filter-branch per questo. per es.

git filter-branch --parent-filter \
'if test $GIT_COMMIT != <sha1ofB>; then cat; fi'

Il risultato è AB-C buttare via il registro commit di A.

Si potrebbe utilizzare rebase interattivo per modificare le ultime due commit prima che sono stati spinti ad una distanza

git rebase HEAD^^ -i

C'è un modo più semplice per fare questo. Supponiamo che sei sul ramo master

Crea un nuovo ramo orfano che rimuoverà tutte commettere storia:

$ git checkout --orphan new_branch

Aggiungi il tuo primo messaggio di commit:

$ git commit -a

Sbarazzarsi del vecchio ramo maestro unmerged:

$ git branch -D master

Rinominare il new_branch ramo corrente master:

$ git branch -m master
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top