Comment supprimer les entrées de journal de validation sélectionnées d'un référentiel Git tout en conservant leurs modifications?

241

Je souhaite supprimer les entrées de journal de validation sélectionnées d'une arborescence de validation linéaire, afin que les entrées ne s'affichent pas dans le journal de validation.

Mon arbre de validation ressemble à ceci:

R--A--B--C--D--E--HEAD

Je voudrais supprimer les entrées B et C afin qu'elles ne s'affichent pas dans le journal de validation, mais les modifications de A à D doivent être conservées. Peut-être en introduisant un seul commit, pour que B et C deviennent BC et que l'arbre ressemble.

R--A--BC--D--E--HEAD

Ou, idéalement, après que A vient directement D. D 'représentant les changements de A à B, B à C et C à D.

R--A--D'--E--HEAD

Est-ce possible? si oui, comment?

Il s'agit d'un projet relativement nouveau, il n'a donc pas de succursales pour l'instant, donc pas de fusion aussi.

xk0der
la source
@ xk0der: "commits" est le bon terme ici. rebasepeut supprimer les anciens / créer de nouveaux commits. Je ne sais pas ce que signifie "valider les entrées du journal".
jfs
@JFSebastian Je ne vois pas de problème avec "journal de validation" - Journal de toutes les validations. Et je voulais supprimer quelques entrées du journal - tout en conservant les modifications réelles (les validations).
xk0der
@ xk0der: les validations git sont adressables par le contenu, c'est-à- dire que si vous modifiez quelque chose dans une validation, par exemple, son message de journal; vous créez un nouveau commit. Vous pouvez lire le commit de git sans git et voir par vous-même .
jfs
@JFSebastian - Merci pour les liens - Je le sais - Mais cette technicité change-t-elle vraiment le problème auquel je faisais face et comment je le pose? Je suppose que non. En fin de compte: je voulais supprimer "les messages du journal de validation" - sans supprimer les "modifications de validation" - Veuillez relire ma question - spécialement le deuxième paragraphe. Pour en ajouter plus, git logaffiche le "journal de validation" git-scm.com/docs/git-log . Et je voulais me débarrasser de deux entrées de ce journal - pas des changements.
xk0der

Réponses:

273

git-rebase (1) fait exactement cela.

$ git rebase -i HEAD~5

git awsome-ness [git rebase --interactive] contient un exemple.

  1. Ne pas utiliser git-rebasesur des validations publiques (distantes).
  2. Assurez-vous que votre répertoire de travail est propre ( commitou stashvos modifications actuelles).
  3. Exécutez la commande ci-dessus. Il lance votre $EDITOR.
  4. Remplacez pickavant Cet Dpar squash. Il fusionnera C et D en B. Si vous souhaitez supprimer un commit, supprimez simplement sa ligne.

Si vous êtes perdu, tapez:

$ git rebase --abort  
jfs
la source
Merci pour la réponse rapide. Alors est-ce que je vérifie A et fais un rebase, quelque chose comme git rebase -i D [A]?
xk0der
3
Comment pouvons-nous le faire sur des dépôts distants?
Eray
6
@Eray: juste push -fvos changements. Ne le faites pas si vous ne travaillez pas seul.
jfs
2
@ ripper234: J'ai corrigé des liens pour pointer le git-rebasemanuel et la machine de retour pour le billet de blog.
jfs
75
# detach head and move to D commit
git checkout <SHA1-for-D>

# move HEAD to A, but leave the index and working tree as for D
git reset --soft <SHA1-for-A>

# Redo the D commit re-using the commit message, but now on top of A
git commit -C <SHA1-for-D>

# Re-apply everything from the old D onwards onto this new place 
git rebase --onto HEAD <SHA1-for-D> master
CB Bailey
la source
Cela fonctionne aussi et m'a aidé à comprendre ce qu'est une réinitialisation logicielle. Certes, la réponse "top" est juste aussi et plus courte, mais merci également pour cette réponse.
cgp
41

Voici un moyen de supprimer un ID de validation spécifique en ne connaissant que l'ID de validation que vous souhaitez supprimer.

git rebase --onto commit-id^ commit-id

Notez que cela supprime réellement la modification introduite par la validation.

rado
la source
7
Le HEAD supplémentaire dans cette commande entraînera la fin de la rebase avec un «HEAD détaché», ce qui n'est pas souhaitable. Il devrait être omis.
Frosty
3
Cela annule les modifications apportées à mon commit-id, l'OP souhaite conserver les modifications, écrase simplement les commits.
CB Bailey
1
-1 car il ne fait pas ce que l'OP a demandé (il détruit plutôt quelque chose qu'il voulait explicitement conserver).
Emil Styrke
1
Bien qu'il ne fasse pas ce que l'OP a demandé, c'était exactement ce dont j'avais besoin, alors +1 pour une réponse utile.
Edvins
20

Pour développer la réponse de JF Sebastian:

Vous pouvez utiliser git-rebase pour apporter facilement toutes sortes de modifications à votre historique de commit.

Après avoir exécuté git rebase --interactive, vous obtenez ce qui suit dans votre $ EDITOR:

pick 366eca1 This has a huge file
pick d975b30 delete foo
pick 121802a delete bar
# Rebase 57d0b28..121802a onto 57d0b28
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit

Vous pouvez déplacer des lignes pour modifier l'ordre des validations et supprimer des lignes pour supprimer cette validation. Ou vous pouvez ajouter une commande pour combiner (écraser) deux validations en une seule validation (la validation précédente est la validation ci-dessus), modifier les validations (ce qui a été modifié) ou reformuler les messages de validation.

Je pense que choisir signifie simplement que vous voulez laisser cet engagement seul.

(L'exemple vient d' ici )

idbrii
la source
14

Vous pouvez supprimer de manière non interactive B et C dans votre exemple avec:

git rebase --onto HEAD~5 HEAD~3 HEAD

ou symboliquement,

git rebase --onto A C HEAD

Notez que les changements en B et C ne seront pas en D; ils seront partis .

Tête
la source
Voir ici pour plus d'informations: sethrobertson.github.io/GitFixUm/fixup.html#remove_deep
Max
3

Encore une façon,

git rebase -i ad0389efc1a79b1f9c4dd6061dca6edc1d5bb78a (C's hash)
and
git push origin master  -f

choisissez le hachage que vous souhaitez utiliser comme base, et la commande ci-dessus devrait le rendre interactif afin que vous puissiez écraser tous les premiers messages (vous devez laisser le plus ancien)

résultats
la source
2

Je trouve ce processus beaucoup plus sûr et plus facile à comprendre en créant une autre branche à partir du SHA1 de A et en sélectionnant les changements souhaités afin de pouvoir m'assurer que je suis satisfait de l'apparence de cette nouvelle branche. Après cela, il est facile de supprimer l'ancienne branche et de renommer la nouvelle.

git checkout <SHA1 of A>
git log #verify looks good
git checkout -b rework
git cherry-pick <SHA1 of D>
....
git log #verify looks good
git branch -D <oldbranch>
git branch -m rework <oldbranch>
Eric Woodruff
la source
si vous faites cela, vous perdrez également le E commit, n'est-ce pas? Si j'ai bien compris, vous supprimez master et renommez retravailler en master (considérant que le flux ABCDE est la branche master).
Renan Bandeira
1

Je viens de rassembler les réponses de toutes les personnes: (m nouveau pour git plz l'utiliser uniquement à titre de référence)

git rebase pour supprimer les commits

git log

-first check from which commit you want to rebase

git rebase -i HEAD ~ 1

-Here i want to rebase on the second last commit- commit count starts from '1')
-this will open the command line editor (called vim editor i guess)

L'écran ressemblera alors à ceci:

pick 0c2236d Ajout d'une nouvelle ligne.

Rebase 2a1cd65..0c2236d sur 2a1cd65 (1 commande)

#

Commandes:

p, pick = utiliser commit

r, reword = utilisez commit, mais modifiez le message de commit

e, edit = utilisez commit, mais arrêtez pour modifier

s, squash = utilisez commit, mais fusionnez avec le commit précédent

f, fixup = comme "squash", mais jetez le message du journal de ce commit

x, exec = exécuter la commande (le reste de la ligne) en utilisant shell

d, drop = supprimer la validation

#

Ces lignes peuvent être réorganisées; ils sont exécutés de haut en bas.

#

Si vous supprimez une ligne ici, cet engagement sera perdu.

#

Cependant, si vous supprimez tout, le rebase sera abandonné.

#

Notez que les validations vides sont commentées ~ ~

~
~
~
~
~
~
~
~
~

Ici, changez la première ligne selon vos besoins (en utilisant les commandes énumérées ci-dessus, c'est-à-dire 'drop' pour supprimer la validation, etc.) Une fois terminé, appuyez sur ': x' pour enregistrer et quitter l'éditeur (c'est pour l'éditeur vim uniquement)

Puis

git push

Si son problème s'affiche, vous devez forcer les modifications à distance (SON TRÈS CRITIQUE: ne forcez pas si vous travaillez en équipe)

git push -f origine

Shrinath Kopare
la source
-1

Vous pouvez utiliser git cherry-pick pour cela. 'cherry-pick' appliquera un commit sur la branche que vous utilisez maintenant.

alors fais

git rebase --hard <SHA1 of A>

puis appliquez les commits D et E.

git cherry-pick <SHA1 of D>
git cherry-pick <SHA1 of E>

Cela sautera la validation B et C. Cela dit, il pourrait être impossible d'appliquer le commit D à la branche sans B, donc YMMV.

Rory
la source
2
L'OP souhaite combiner les validations B, C, D, sans supprimer leurs modifications.
jfs
3
Je pense que tu voulais dire reset --hard, pas rebase --hard(qui n'existe pas)
Mauricio Scheffer