Je soumets généralement une liste de commits pour examen. Si j'ai les commits suivants:
HEAD
Commit3
Commit2
Commit1
... Je sais que je peux modifier head commit avec git commit --amend
. Mais comment puis-je modifier Commit1
, étant donné que ce n'est pas le HEAD
commit?
git
git-rewrite-history
Sam Liao
la source
la source
Réponses:
Vous pouvez utiliser git rebase . Par exemple, si vous souhaitez modifier la validation
bbc643cd
, exécutezVeuillez noter le
^
signe d'insertion à la fin de la commande, car vous devez en fait rebaser le commit avant celui que vous souhaitez modifier .Dans l'éditeur par défaut, modifiez
pick
enedit
dans la ligne mentionnant «bbc643cd».Enregistrez le fichier et quittez: git interprétera et exécutera automatiquement les commandes du fichier. Vous vous retrouverez dans la situation précédente dans laquelle vous venez de créer un commit
bbc643cd
.À ce stade,
bbc643cd
c'est votre dernier commit et vous pouvez facilement le modifier : apportez vos modifications puis validez-les avec la commande:Après cela, tapez:
pour revenir à la validation HEAD précédente.
AVERTISSEMENT : notez que cela changera le SHA-1 de ce commit ainsi que tous les enfants - en d'autres termes, cela réécrit l'historique à partir de ce point. Vous pouvez interrompre les dépôts en faisant cela si vous poussez à l'aide de la commande
git push --force
la source
reword
action dansgit rebase -i
au lieu deedit
(il ouvre automatiquement l'éditeur et continue avec le reste des étapes de rebase; cela évite l'utilisationgit commit --ammend
etgit rebase --continue
lorsque vous avez seulement besoin de modifier le message de validation et non le contenu ).git stash
avantgit rebase
etgit stash pop
après, si vous avez des modifications en attente.git commit --all --amend --no-edit
ici. Tout ce que j'avais à faire après,git rebase -i ...
c'était de le fairegit commit --amend
normalementgit rebase --continue
.Utilisez le rebase interactif génial:
Recherchez le commit que vous souhaitez, passez
pick
àe
(edit
), puis enregistrez et fermez le fichier. Git reviendra à ce commit, vous permettant soit:git commit --amend
pour apporter des modifications, ougit reset @~
pour ignorer le dernier commit, mais pas les modifications apportées aux fichiers (c'est-à-dire vous amener au point où vous en étiez lorsque vous aviez modifié les fichiers, mais que vous n'aviez pas encore engagé).Ce dernier est utile pour faire des choses plus complexes comme le fractionnement en plusieurs validations.
Ensuite, exécutez
git rebase --continue
et Git rejouera les modifications suivantes au-dessus de votre commit modifié. Vous pouvez être invité à résoudre certains conflits de fusion.Remarque:
@
est un raccourci pourHEAD
, et~
est le commit avant le commit spécifié.En savoir plus sur la réécriture de l'historique dans les documents Git.
N'ayez pas peur de rebaser
ProTip ™: N'ayez pas peur d'expérimenter avec des commandes "dangereuses" qui réécrivent l'historique * - Git ne supprime pas vos validations pendant 90 jours par défaut; vous pouvez les trouver dans le reflog:
* Méfiez-vous des options comme
--hard
et--force
bien - ils peuvent éliminer les données.* De plus, ne réécrivez pas l'historique sur les branches sur lesquelles vous collaborez.
Sur de nombreux systèmes,
git rebase -i
Vim ouvrira par défaut. Vim ne fonctionne pas comme la plupart des éditeurs de texte modernes, alors regardez comment rebaser avec Vim . Si vous préférez utiliser un autre éditeur, changez-le avecgit config --global core.editor your-favorite-text-editor
.la source
@
comme raccourciHEAD
. Merci d'avoir posté ça.git reset @~
exactement ce que je voulais faire après avoir choisi de validergit rebase ...
. Tu es mon héros)Le rebasage interactif avec
--autosquash
est quelque chose que j'utilise fréquemment lorsque j'ai besoin de corriger des validations précédentes plus profondément dans l'histoire. Cela accélère essentiellement le processus illustré par la réponse de ZelluX et est particulièrement pratique lorsque vous avez plus d'un commit que vous devez modifier.De la documentation:
Supposons que vous ayez une histoire qui ressemble à ceci:
et vous souhaitez apporter des modifications à Commit2, puis validez vos modifications à l'aide de
Alternativement, vous pouvez utiliser le commit-sha au lieu du message de validation,
"fixup! e8adec4
ou même juste un préfixe du message de validation.Ensuite, lancez un rebase interactif sur la validation avant
votre éditeur s'ouvrira avec les commits déjà correctement commandés
il vous suffit de sauvegarder et de quitter
la source
git commit --fixup=@~
au lieu degit commit -m "fixup! Commit2"
. Ceci est particulièrement utile lorsque vos messages de validation sont plus longs et qu'il serait difficile de taper le tout.Courir:
$ git rebase --interactive commit_hash^
chacun
^
indique le nombre de validations que vous souhaitez modifier, s'il ne s'agit que d'une seule (le hachage de validation que vous avez spécifié), il vous suffit d'en ajouter une^
.En utilisant Vim vous changez les mots
pick
pourreword
les commits que vous souhaitez modifier, sauvegarder et quitter (:wq
). Ensuite, git vous demandera à chaque commit que vous avez marqué comme reformulé afin que vous puissiez changer le message de commit.Chaque message de validation que vous devez enregistrer et quitter (
:wq
) pour passer au message de validation suivantSi vous souhaitez quitter sans appliquer les modifications, appuyez sur
:q!
EDIT : pour naviguer dans
vim
vous utilisezj
pour monter,k
pour descendre,h
pour aller à gauche etl
pour aller à droite (tout cela enNORMAL
mode, appuyezESC
pour aller enNORMAL
mode). Pour modifier un texte, appuyez suri
pour accéder auINSERT
mode dans lequel vous insérez du texte. AppuyezESC
pour revenir enNORMAL
mode :)MISE À JOUR : Voici un excellent lien de la liste github Comment annuler (presque) n'importe quoi avec git
la source
git push --force
?git push --force
qui remplace les commits à distance par vos commits locaux. Ce n'est pas le cas de ce sujet :)Si, pour une raison quelconque, vous n'aimez pas les éditeurs interactifs, vous pouvez utiliser
git rebase --onto
.Dites que vous souhaitez modifier
Commit1
. Tout d'abord, branchez d' avantCommit1
:Deuxièmement, saisissez
Commit1
aveccherry-pick
:Maintenant, modifiez vos modifications en créant
Commit1'
:Et enfin, après avoir caché tout autre changement, transplantez le reste de vos commits au-
master
dessus de votre nouveau commit:Lire: "rebaser, sur la branche
amending
, tous les commits entreCommit1
(non inclus) etmaster
(inclus)". Autrement dit, Commit2 et Commit3, coupant entièrement l'ancien Commit1. Vous pouvez simplement les choisir, mais cette méthode est plus facile.N'oubliez pas de nettoyer vos succursales!
la source
git checkout -b amending Commit1~1
pour obtenir le commit préalablegit checkout -b amending Commit1
?Basé sur la documentation
Modification du message d'anciens ou de plusieurs messages de validation
Ce qui précède affiche une liste des 3 derniers validations sur la branche actuelle, changez 3 en quelque chose d'autre si vous en voulez plus. La liste ressemblera à ce qui suit:
Remplacez pick par reword avant chaque message de validation que vous souhaitez modifier. Supposons que vous modifiez le deuxième commit de la liste, votre fichier ressemblera à ceci:
Enregistrez et fermez le fichier de liste de validation, cela fera apparaître un nouvel éditeur pour vous permettre de modifier votre message de validation, de modifier le message de validation et de l'enregistrer.
Finalement, appuyez sur les commits modifiés.
la source
Commande complètement non interactive (1)
Je pensais juste partager un alias que j'utilise pour cela. Il est basé sur un rebase interactif non interactif. Pour l'ajouter à votre git, exécutez cette commande (explication donnée ci-dessous):
Le plus grand avantage de cette commande est le fait qu'il ne s'agit pas de vim .
(1) étant donné qu'il n'y a pas de conflits lors du rebasage, bien sûr
Usage
Le nom
amend-to
semble approprié à mon humble avis. Comparez le flux avec--amend
:Explication
git config --global alias.<NAME> '!<COMMAND>'
- crée un alias git global nommé<NAME>
qui exécutera la commande non-git<COMMAND>
f() { <BODY> }; f
- une fonction bash "anonyme".SHA=`git rev-parse "$1"`;
- convertit l'argument en révision git, et affecte le résultat à la variableSHA
git commit --fixup "$SHA"
- fixup-commit pourSHA
. Voir lesgit-commit
documentsGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
une partie a été couverte par d'autres réponses.--autosquash
est ce qui est utilisé en conjonction avecgit commit --fixup
, voir lesgit-rebase
documents pour plus d'informationsGIT_SEQUENCE_EDITOR=true
est ce qui rend le tout non interactif. Ce hack que j'ai appris de ce billet de blog .la source
amend-to
gérer des fichiers non stadés:git config --global alias.amend-to '!f() { SHA=
git rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
Modification de rebase interactive automatisée suivie d'un retour de validation prêt pour une refonte
Je me suis retrouvé à corriger un commit passé assez fréquemment pour que j'écrive un script pour cela.
Voici le workflow:
Cela vous déposera au commit que vous souhaitez modifier.
Corrigez et organisez le commit comme vous le souhaitiez en premier lieu.
(Vous voudrez peut-être utiliser
git stash save
pour conserver tous les fichiers que vous ne commettez pas)Refaire le commit avec
--amend
, par exemple:Terminez le rebase:
Pour que ce qui précède fonctionne, placez le script ci-dessous dans un fichier exécutable appelé
git-commit-edit
quelque part dans votre$PATH
:la source
Entré dans cette approche (et c'est probablement exactement la même chose que l'utilisation de rebase interactif) mais pour moi, c'est un peu simple.
Remarque: Je présente cette approche dans le but d'illustrer ce que vous pouvez faire plutôt que comme une alternative quotidienne. Puisqu'il comporte de nombreuses étapes (et éventuellement quelques mises en garde.)
Dites que vous souhaitez modifier le commit
0
et que vous êtes actuellement surfeature-branch
Commander à ce commit et créer un
quick-branch
. Vous pouvez également cloner votre branche de fonctionnalité en tant que point de récupération (avant de commencer).Vous allez maintenant avoir quelque chose comme ça:
Les changements de scène, cachent tout le reste.
Validez les modifications et revenez à
feature-branch
Vous allez maintenant avoir quelque chose comme ça:
Rebaser
feature-branch
surquick-branch
(résoudre tout conflit en cours de route). Appliquer la cachette et retirerquick-branch
.Et vous vous retrouvez avec:
Git ne dupliquera pas (bien que je ne puisse pas vraiment dire dans quelle mesure) le commit 0 lors du rebasage.
Remarque: tous les hachages de validation sont modifiés à partir de la validation que nous avions initialement l'intention de modifier.
la source
Pour obtenir une commande non interactive, mettez un script avec ce contenu dans votre PATH:
Utilisez-le en mettant en scène vos modifications (avec
git add
), puis exécutezgit fixup <commit-to-modify>
. Bien sûr, il restera interactif si vous rencontrez des conflits.la source
git stash
+rebase
automatisationPour quand j'ai besoin de modifier un ancien commit beaucoup de fois pour les revues Gerrit, j'ai fait:
GitHub en amont .
Usage:
git add
s'il est déjà en dépôtgit-amend-old $old_sha
J'aime cela
--autosquash
car il n'écrase pas les autres corrections non liées.la source
git amend
pour appliquer des modifications à un commit spécifique avec l'utilisation de la cachette actuelle, très intelligent!J'ai résolu ça,
1) en créant un nouveau commit avec les changements que je veux ..
2) Je sais quel engagement j'ai besoin de fusionner avec lui. qui est commit 3.
donc,
git rebase -i HEAD~4
# 4 représente les 4 derniers commit (ici le commit 3 est à la 4ème place)3) dans le rebasage interactif, la validation récente sera située en bas. il se ressemblera,
4) ici, nous devons réorganiser la validation si vous souhaitez fusionner avec une spécification spécifique. ça devrait être,
après la réorganisation, vous devez remplacer
p
pick
parf
(la correction se fusionnera sans message de validation) ous
(la fusion de squash avec le message de validation peut changer en cours d'exécution)puis enregistrez votre arbre.
fusionner maintenant fait avec commit existant.
la source
La meilleure option consiste à utiliser la "commande de rebase interactive" .
Maintenant, comment utiliser cette commande?
-i
signifie "interactif" . Notez que vous pouvez effectuer un rebase en mode non interactif. ex:HEAD
indique votre emplacement actuel (peut également être un nom de branche ou valider SHA). Le~n
moyen "n beforeé, doncHEAD~n
sera donc la liste des" n "commits avant celui sur vous êtes actuellement.git rebase
a une commande différente comme:p
oupick
pour garder le commit tel quel.r
oureword
: pour conserver le contenu du commit mais modifier le message de commit.s
ousquash
: pour combiner les modifications de ce commit dans le commit précédent (le commit au dessus dans la liste).... etc.
Remarque: Il est préférable de faire fonctionner Git avec votre éditeur de code pour simplifier les choses. Comme par exemple si vous utilisez du code visuel, vous pouvez ajouter comme ceci
git config --global core.editor "code --wait"
. Ou vous pouvez rechercher dans Google comment associer votre éditeur de code préféré avec GIT.Exemple de
git rebase
Je voulais changer les 2 derniers commits que j'ai faits alors je traite comme ceci:
Maintenant, j'utilise
git rebase
pour changer les 2 derniers messages de commit:$git rebase -i HEAD~2
Il ouvre l'éditeur de code et montre ceci:Puisque je veux changer le message de commit pour ces 2 commits. Je vais donc taper
r
oureword
à la place depick
. Enregistrez ensuite le fichier et fermez l'onglet. Notez que celarebase
est exécuté dans un processus en plusieurs étapes, la prochaine étape consiste donc à mettre à jour les messages. Notez également que les validations sont affichées dans l'ordre chronologique inverse de sorte que la dernière validation est affichée dans celle-ci et la première validation dans la première ligne et ainsi de suite.Mettre à jour les messages: mettre à jour le premier message:
enregistrer et fermer Modifier le deuxième message
sauver et fermer.
Vous obtiendrez un message comme celui-ci à la fin du rebase:
Successfully rebased and updated refs/heads/documentation
ce qui signifie que vous réussissez. Vous pouvez afficher les modifications:Je souhaite que cela puisse aider les nouveaux utilisateurs :).
la source
Pour moi, c'était pour supprimer certaines informations d'identification d'un dépôt. J'ai essayé de rebaser et j'ai rencontré une tonne de conflits apparemment sans rapport en cours de route pour essayer de rebaser - continuer. Ne vous embêtez pas à essayer de vous rebaser, utilisez l'outil appelé BFG (brew install bfg) sur mac.
la source
Si vous n'avez pas encore poussé les validations, vous pouvez revenir à une validation précédente en utilisant
git reset HEAD^[1,2,3,4...]
Par exemple
Oups, j'ai oublié d'ajouter file2 au premier commit ...
Cela ajoutera file2 au premier commit.
la source
Eh bien, cette solution peut sembler très stupide, mais peut vous sauver dans certaines conditions.
Un de mes amis vient de commettre accidentellement de très gros fichiers (quatre fichiers auto-générés allant de 3 Go à 5 Go chacun), puis a fait des validations de code supplémentaires en plus de cela avant de réaliser le problème qui
git push
ne fonctionnait plus!Les fichiers avaient été répertoriés
.gitignore
mais après avoir renommé le dossier du conteneur, ils ont été exposés et validés! Et maintenant, il y avait quelques autres validations du code en plus de cela, maispush
fonctionnait pour toujours (essayant de télécharger des Go de données!) Et finalement échouerait en raison des limites de taille de fichier de Github .Le problème avec rebase interactif ou quelque chose de similaire était qu'ils traiteraient de fouiller ces fichiers énormes et prendraient une éternité pour faire quoi que ce soit. Néanmoins, après avoir passé près d'une heure dans la CLI, nous ne savions pas si les fichiers (et les deltas) étaient réellement supprimés de l'historique ou tout simplement pas inclus dans les validations actuelles. La poussée ne fonctionnait pas non plus et mon ami était vraiment coincé.
Donc, la solution que j'ai trouvée était:
~/Project-old
.~/Project
).cp -r
les fichiers du~/Project-old
dossier vers~/Project
.mv
édités et inclus dans.gitignore
correctement..git
dossier dans le dossier récemment cloné.~/Project
par l'ancien. C'est là que vivent les journaux de l'histoire problématique!push
édité.Le plus gros problème avec cette solution est qu'elle traite de la copie manuelle de certains fichiers et qu'elle fusionne toutes les validations récentes en une seule (évidemment avec un nouveau hash de validation). B
Les grands avantages sont que, c'est très clair à chaque étape, cela fonctionne très bien pour les fichiers énormes (ainsi que les fichiers sensibles) , et il ne laisse aucune trace dans l'histoire!
la source