Question

    

Cette question a déjà une réponse ici:

         

Avec git rebase --interactive <commit> vous pouvez écraser un certain nombre de commits ensemble en une seule.

C'est tout grand à moins que vous voulez le squash engage dans la première commettras. Cela semble impossible de le faire.

Y a-t-il des moyens d'y parvenir?


Modérément liés:

Dans une question connexe, j'ai réussi à trouver une approche différente de la nécessité de squashing contre le premier engagement, ce qui est bien, pour en faire le second.

Si vous êtes intéressé: git: comment insérer un commit comme le premier, le changement de tous les autres

Était-ce utile?

La solution

Mise à jour Juillet 2012 ( git 1.7.12 + )

Vous pouvez maintenant rebasage tous les verse jusqu'à la racine, et sélectionnez le deuxième engagement Y à la première écrasée X.

git rebase -i --root master

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

Cette commande peut maintenant être utilisé pour réécrire toute l'histoire qui mène de « $tip » jusqu'à la racine allouent.

Voir engager df5df20c1308f936ea542c86df1e9c6974168472 sur GitHub Chris Webb (arachsys) .


Réponse originale (Février 2009)

Je crois que vous trouverez différentes recettes pour que la question SO " Comment puis-je combiner les deux premiers commits d'un dépôt git? "

Charles Bailey condition que le plus réponse détaillée, nous rappelant que commit est un arbre complet (pas seulement diffs à partir d'un état précédent).
Et là, l'ancien commettras (le « commit initial ») et le nouveau commit (résultat de la squashing) n'a aucun ancêtre commun.
Cela signifie que vous ne pouvez pas « commit --amend » initial engager dans une nouvelle, puis rebase sur la nouvelle initiale commettras l'histoire de la première précédente commit (beaucoup de conflits)

(Cette dernière phrase n'est plus vrai avec git rebase -i --root <aBranch>)

Au lieu (avec A le "commit" initial original, et B une validation ultérieure devait être écrasé dans l'une initiale):

  1. Retour à la dernière livraison que nous voulons former le commit initial (détacher HEAD):

    git checkout <sha1_for_B>
    
  2. Réinitialiser le pointeur de la branche à la commettras initiale, mais en laissant l'indice et de travail intact arbre:

    git reset --soft <sha1_for_A>
    
  3. Modifier l'arbre initial à l'aide de l'arbre 'B':

    git commit --amend
    
  4. marquer temporairement ce nouveau commit initial (ou vous pouvez rappeler le nouveau commit SHA1 manuellement):

    git tag tmp
    
  5. Retour à la branche d'origine (en supposant maître pour cet exemple):

    git checkout master
    
  6. Replay tous les commits après B sur le nouveau commit initial:

    git rebase --onto tmp <sha1_for_B>
    
  7. Supprimer la balise temporaire:

    git tag -d tmp
    

De cette façon, la « rebase --onto » ne pas introduire de conflit lors de la fusion, car il rebases l'histoire fait après le dernier commit (B) à Squashed dans une première (qui était A) à tmp (représentant le squashed nouveau commit initial): avance rapide trivial se fond uniquement.

Cela fonctionne pour « A-B », mais aussi « A-...-...-...-B » (un certain nombre de commits peut être écrasé dans une première de cette façon)

Autres conseils

Je l'ai retravaillé le script de VonC tout faire automatiquement et ne me demandez pas quoi que ce soit. Vous donnez deux commit SHA1s et il écrasera tout entre eux dans un commit nommé « histoire aplaties »:

#!/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

Pour ce que ça vaut, j'éviter ce problème en créant toujours un « non-op » premier commit, dans lequel la seule chose dans le référentiel est un .gitignore vide:

https://github.com/DarwinAwardWinner/ git-mesure-commandes / blob / maître / bin / git-MyInit

De cette façon, il n'y a jamais aucune raison de jouer avec la première validation.

Si vous voulez simplement écraser tous les engage dans un seul commit initial, juste réinitialiser le référentiel et modifier le premier commit:

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

reset Git laissera l'arbre de travail intact, donc tout est encore là. Donc, il suffit d'ajouter les fichiers à l'aide des commandes git add et modifiant la première commettras avec ces changements. Par rapport à rebase -i vous perdrez la possibilité de fusionner les commentaires git bien.

écrasera deuxième engagement dans le premier:

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

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

message de validation pour AB sera prélevé B (bien que je préfère de A).

a le même effet que la réponse de Uwe Kleine-König, mais travaille pour un non initial ainsi.

Squashing la première et la seconde engager entraînerait la première commit être réécrit. Si vous avez plus d'une branche qui est basé sur la première validation, vous auriez coupé cette branche.

Prenons l'exemple suivant:

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

Squashing a et b dans un nouveau commit "ab" conduirait à deux arbres distincts qui, dans la plupart des cas n'est pas souhaitable, car git-merge et git-rebase ne fonctionnent plus dans les deux branches.

ab---HEAD

a---d

Si vous voulez vraiment cela, il peut être fait. Jetez un oeil à l'outil git-filtre branche pour un puissant (et dangereux) pour ré-écriture de l'histoire.

Vous pouvez utiliser le filtre-branche git pour cela. par exemple.

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

Il en résulte AB-C jeter le commit journal de A.

Vous pouvez utiliser rebase interactif pour modifier les deux derniers commits avant qu'ils ont été poussés à une télécommande

git rebase HEAD^^ -i

Il y a un moyen plus facile de le faire. Supposons que vous êtes sur la branche master

Créer une nouvelle branche qui supprimera orphelins à cause toute l'histoire commit:

$ git checkout --orphan new_branch

Ajoutez votre commit initial message:

$ git commit -a

Débarrassez-vous de l'ancienne branche principale unmerged:

$ git branch -D master

Renommer votre new_branch courant de branche à master:

$ git branch -m master
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top