Comment écraser les commits en git après les avoir poussés?

551

Cela donne une bonne explication de l'écrasement de plusieurs validations:

http://git-scm.com/book/en/Git-Branching-Rebasing

mais cela ne fonctionne pas pour les commits qui ont déjà été poussés. Comment écraser les dernières validations dans mes référentiels local et distant?

EDIT: Quand je le fais git rebase -i origin/master~4 master, conservez le premier comme pick, définissez les trois autres comme squash, puis quittez (via cx cc dans emacs), j'obtiens:

$ git rebase -i origin/master~4 master
# Not currently on any branch.
nothing to commit (working directory clean)

Could not apply 2f40e2c... Revert "issue 4427: bpf device permission change option added"
$ git rebase -i origin/master~4 master
Interactive rebase already started

où 2f40 est le pickcommit. Et maintenant, aucun des 4 commits n'apparaît git log. Je m'attendais à ce que mon éditeur soit redémarré pour que je puisse saisir un message de validation. Qu'est-ce que je fais mal?

Loren
la source

Réponses:

781

Squash s'engage localement avec

git rebase -i origin/master~4 master

puis forcer la poussée avec

git push origin +master

Différence entre --forceet+

À partir de la documentation de git push:

Notez que cela --forces'applique à toutes les références qui sont poussées, donc l'utiliser avec un push.defaultensemble matchingou plusieurs destinations push configurées avec remote.*.pushpeut remplacer les références autres que la branche actuelle (y compris les références locales qui sont strictement derrière leur homologue distant). Pour forcer une poussée sur une seule branche, utilisez un + devant la refspec pour pousser (par exemple git push origin +masterpour forcer une poussée sur la masterbranche).

Alan Haggai Alavi
la source
30
vous pouvez aussigit push --force origin master
Daenyth
7
Daenyth : Oui, mais je préfère toujours cette syntaxe car elle est plus courte.
Alan Haggai Alavi
86
Et bien sûr, réalisez que si quelqu'un d'autre a pu se retirer du référentiel distant, vous ne voulez probablement pas le faire - la réponse dans ce cas est "vous ne le faites pas".
Cascabel
10
En outre, je pense que l'OP copie exactement la commande git rebase -i origin/masteret veut réellement savoir comment rebaser les commits plus loin que cela, par exemple git rebase -i origin/master~20 master.
Cascabel
6
gstackoverflow :+force uniquement la refspec qui est préfixée par elle. --forceforcera toutes les refspecs à être poussées. Veuillez consulter la réponse mise à jour.
Alan Haggai Alavi
120

Sur une branche j'ai pu le faire comme ça (pour les 4 derniers commits)

git checkout my_branch
git reset --soft HEAD~4
git commit
git push --force origin my_branch
jakob-r
la source
1
Faire cela avec la commande douce sur une branche déjà poussée a fini par pousser une tonne d'autres personnes à commettre pour moi.
cchamberlain
3
Une tonne? Comment peut-il être plus de 4? Peux-tu élaborer?
jakob-r
Je n'en suis pas sûr, mais cela a quelque chose à voir avec le fait d'écraser un commit déjà poussé. On dirait que d'autres ont vécu la même
chose
4
J'aurais accepté cela comme réponse attendue. Plus propre que la réponse acceptée.
vikramvi
4
C'est la réponse la plus claire et acceptée en seulement 4 étapes
Ameya Salagre
45

Différence mineure par rapport à la réponse acceptée, mais j'avais beaucoup de difficulté à écraser et j'ai finalement compris.

$ git rebase -i HEAD~4
  • Sur l'écran interactif qui s'ouvre, remplacez pick par squash en haut pour tous les commits que vous souhaitez écraser.
  • Enregistrez et fermez l'éditeur via esc --> :wq

Poussez vers la télécommande en utilisant:

$ git push origin branch-name --force
BLRBoy
la source
2
bref et efficace, élaboré:
terwxqian
22

De nombreux problèmes peuvent être évités en créant uniquement un branchsur lequel travailler et ne pas travailler sur master:

git checkout -b mybranch

Les travaux suivants s'appliquent aux remotevalidations déjà poussées et un mélange de remotevalidations poussées / localvalidations uniquement:

# example merging 4 commits

git checkout mybranch
git rebase -i mybranch~4 mybranch

# at the interactive screen
# choose fixup for commit: 2 / 3 / 4

git push -u origin +mybranch

J'ai également quelques notes de demande de tirage qui peuvent être utiles.

Stuart Cardall
la source
17

git rebase -i master

vous obtiendrez l'éditeur vm ouvert et msgs quelque chose comme ça

Pick 2994283490 commit msg1
f 7994283490 commit msg2
f 4654283490 commit msg3
f 5694283490 commit msg4
#Some message 
#
#some more

Ici, j'ai changé le choix de tous les autres commits en "f" (Stands for fixup).

git push -f origin feature/feature-branch-name-xyz

cela corrigera toutes les validations en une seule validation et supprimera toutes les autres validations. Je l'ai fait et cela m'a aidé.

Nupur
la source
3

Lorsque vous travaillez avec un Gitlab ou un Github, vous pouvez rencontrer des problèmes de cette manière. Vous écrasez vos commits avec l'une des méthodes ci-dessus. Mon préféré est:

git rebase -i HEAD~4
or
git rebase -i origin/master

sélectionnez squash ou fixup pour le vôtre. À ce stade, vous devriez vérifier l'état de git. Et le message pourrait être:

    On branch ABC-1916-remote
    Your branch and 'origin/ABC-1916' have diverged,
    and have 1 and 7 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)

Et vous pouvez être tenté de le tirer. NE FAITES PAS CELA ou vous serez dans la même situation qu'auparavant.

Poussez plutôt vers votre origine avec:

git push origin +ABC-1916-remote:ABC-1916

Les + permettent de forcer la poussée sur une seule branche.

Alex
la source
il n'y a rien de mal à tirer, surtout si vous avez des conflits, ils peuvent être résolus plus facilement que si vous forcez la poussée
Ray_Poly
2

Pour écraser deux commits, dont l'un a déjà été poussé, sur une même branche, les opérations suivantes ont fonctionné:

git rebase -i HEAD~2
    [ pick     older-commit  ]
    [ squash   newest-commit ]
git push --force

Par défaut, cela inclura le message de validation du dernier commit en tant que commentaire sur l'ancien commit.

les homards
la source
2

1) git rebase -i HEAD~4

Pour élaborer: Il fonctionne sur la branche actuelle; le HEAD ~ 4 signifie écraser les quatre derniers commits; mode interactif (-i)

2) À ce stade, l'éditeur a ouvert, avec la liste des validations, pour modifier la deuxième validation et les suivantes, en remplaçant pick par squash puis en l'enregistrant.

sortie: refs / têtes / nom de branche correctement rebasés et mis à jour.

3) git push origin refs/heads/branch-name --force

production:

remote:
remote: To create a merge request for branch-name, visit:
remote: http://xxx/sc/server/merge_requests/new?merge_request%5Bsource_branch%5D=sss
remote:To ip:sc/server.git
 + 84b4b60...5045693 branch-name -> branch-name (forced update)
terwxqian
la source