Comment puis-je pousser un commit spécifique vers une télécommande, et pas les validations précédentes?

Réponses:

1087

Pour remonter un commit donné, vous pouvez écrire:

git push <remotename> <commit SHA>:<remotebranchname>

fourni <remotebranchname>existe déjà sur la télécommande. (Si ce n'est pas le cas, vous pouvez l'utiliser git push <remotename> <commit SHA>:refs/heads/<remotebranchname>pour le créer automatiquement.)

Si vous voulez pousser un commit sans pousser les commits précédents, vous devez d'abord utiliser git rebase -ipour réorganiser les commits.

Geoff Reedy
la source
66
git push <remotename> <commit SHA>:<remotebranchname>travaux. l'astuce consiste à le combiner avec git rebase -ipour déplacer le commit que vous voulez en tant que premier commit, et à spécifier que commit-sha
dminer
29
une autre bonne astuce est de vous assurer que vous copiez le SHA du commit que vous voulez pousser après avoir fait ce rebase -i, et pas avant, comme je viens de le faire :)
estan
33
N'oubliez pas que cela échoue si la branche distante n'existe pas encore. La création de la branche peut se faire avec git push <remotename> <commit SHA>:refs/heads/<new remote branch name>. Après cela, appuyez sur comme décrit dans la réponse.
Wes Oldenbeuving
33
Par exemple, pour pousser tout sauf le dernier commit avec des noms standard git push origin HEAD~1:master.
bruit sans art
3
Notez également que si vous avez déjà poussé un SHA ultérieur vers cette branche distante, vous devrez forcer celui-ci. Utilisez le -fdrapeau.
Ian Vaughan
79

Les autres réponses manquent sur les descriptions de réorganisation.

git push <remotename> <commit SHA>:<remotebranchname>

poussera un seul commit, mais ce commit doit être le plus ancien de vos commits locaux, non poussés, à ne pas confondre avec le top, first ou tip commit, qui sont toutes des descriptions ambiguës à mon avis. Le commit doit être le plus ancien de vos commit, c'est-à-dire le plus éloigné de votre commit le plus récent. Si ce n'est pas la plus ancienne validation, toutes les validations de votre SHA local, non poussé le plus ancien vers le SHA spécifié seront poussées. Pour réorganiser les validations, utilisez:

git rebase -i HEAD~xxx

Après avoir réorganisé la validation, vous pouvez la pousser en toute sécurité vers le référentiel distant.

Pour résumer, j'ai utilisé

git rebase -i HEAD~<number of commits to SHA>
git push origin <post-rebase SHA>:master

pour pousser un seul commit sur ma branche maître distante.

Références:

  1. http://blog.dennisrobinson.name/push-only-one-commit-with-git/
  2. http://blog.dennisrobinson.name/reorder-commits-with-git/

Voir également:

  1. git: Duplicate valide après rebase local suivi par Pull
  2. git: pousser les commits simples, réorganiser avec rebase, commettre en double
Samuel
la source
3
Il semble que certaines origines ne le permettent pas. Par exemple, avec GitLab, je vois "Vous n'êtes pas autorisé à forcer le code push vers une branche protégée sur ce projet.". Ce qui est un peu étrange car je ne pensais pas forcer quoi que ce soit, je faisais juste un push normal. Une idée comment le faire sans «forcer»?
Ed Avis
1
@Ed Shoud n'a pas besoin de forcer la poussée. On dirait que vous avez un problème avec votre configuration git spécifique. Vous avez peut-être rebasé après le commit HEAD distant? Je ne sais pas ce qu'est une branche protégée, cela ressemble à un problème d'autorisation.
Samuel
1
Samuel - cela aurait du sens, mais git rebase -i ne vous montre que les commits locaux qui sont postérieurs au HEAD distant, donc je ne sais pas comment j'aurais pu faire ça.
Ed Avis
1
Samuel - en effet, je peux faire des push partiels maintenant, donc je ne sais pas ce qui s'est mal passé, mais il doit avoir essayé de pousser un commit non dérivé de HEAD distant d'une manière ou d'une autre.
Ed Avis
1
@Ed Vous avez dit "git rebase -i ne vous montre que les commits locaux qui sont postérieurs au HEAD distant", je ne pense pas que ce soit vrai. J'ai testé et j'ai pu rebaser la tête distante.
Samuel
25

Je suggère d'utiliser git rebase -i; déplacez le commit que vous souhaitez pousser vers le haut des commits que vous avez effectués. Ensuite, utilisez git logpour obtenir le SHA du commit rebasé, vérifiez-le et poussez-le. Le rebase aura fait en sorte que tous vos autres validations soient désormais des enfants de celui que vous avez poussé, donc les futures poussées fonctionneront bien aussi.

Walter Mundt
la source
3
Pourriez-vous peut-être donner un exemple complet de mouvement esp. re l' git logétape?
Drux
4
Supposons que vous ayez 3 validations relativement indépendantes avec les messages "A", "B", "C" validés dans cet ordre et que vous vouliez appuyer sur "B". «git rebase -i» devrait vous permettre, ainsi qu'à l'éditeur, de répertorier les trois; déplacer B vers le haut et enregistrer / quitter. 'git log --pretty = oneline -n3' affichera B, A, C avec des hachages avant chaque message, B étant maintenant le dernier. 'git checkout -b temp $ hash_of_B; git push 'devrait pousser B à ce point. Vous voudrez alors probablement 'git checkout -b master; git branch -d temp 'pour revenir à votre état précédent, en supposant que vous étiez sur votre branche maître locale; remplacer le cas échéant.
Walter Mundt
1
+1 Avez-vous déjà rencontré la «colère des dieux git» après rebase-push-rebase? (Cela pourrait également arriver par accident, non?)
Drux
2
Si vous lisez attentivement ma réponse, vous voyez que le push ne se produit qu'après le rebase, et la validation rebasée n'est déplacée qu'au-dessus des autres validations qui n'ont pas encore été poussées. Une fois qu'un commit est poussé, il doit généralement être considéré comme figé; laissez-le tranquille lors du rebasage futur. Cette technique sert uniquement à trier plusieurs modifications locales dans un bon ordre avant de les pousser. Si le suivi est correctement configuré, `` git rebase -i '' sans aucun autre argument par défaut ne montrera même pas que vous avez poussé les commits, il est donc plus sûr des accidents que certaines autres méthodes.
Walter Mundt
21

Cherry-pick fonctionne mieux que toutes les autres méthodes tout en poussant un commit spécifique.

La façon de le faire est:

Créer une nouvelle branche -

git branch <new-branch>

Mettez à jour votre nouvelle succursale avec votre succursale d'origine -

git fetch

git rebase

Ces actions vous assureront que vous avez exactement les mêmes éléments que votre origine.

Choisissez le sha idque vous voulez faire pousser -

git cherry-pick <sha id of the commit>

Vous pouvez l'obtenir sha iden exécutant

git log

Poussez-le à votre origine -

git push

Courez gitkpour voir que tout ressemble à ce que vous vouliez.

David
la source
2
L'utilisation git rebase -isera la solution idéale comme suggéré dans les solutions ci-dessus. Cherry pick ne doit être utilisé que lorsque vous souhaitez dupliquer la validation.
Vinay Bhargav
13

Je crois que vous devriez "git revenir" à cet engagement, puis le pousser. Ou vous pouvez effectuer cherry-pickune validation dans une nouvelle branche et la transmettre à la branche du référentiel distant. Quelque chose comme:

git branch onecommit
git checkout onecommit
git cherry-pick 7300a6130d9447e18a931e898b64eefedea19544 # From the other branch
git push origin {branch}
Josh K
la source
9
git revert est une mauvaise idée ici - il crée un nouveau commit
hasen
1
@hasen: Vous pouvez alors simplement cherry-pickvalider.
Josh K
4
revenir à la fois et choisir les cerises sont de mauvaises idées. git rebase -i est votre ami ici, voir la réponse de Walter Mundt ci-dessous.
Nicolas C
3
@Nicolas, pourquoi choisir les cerises est-il une mauvaise idée?
Antoine
3
@Antoine, vous souhaitez généralement que votre branche reste synchronisée avec celle qu'elle suit à l'origine. Si vous choisissez, vous faites un copier / coller et vous devrez à un moment donné gérer la copie non poussée. Si vous rebasez -i, vous "coupez et collez" et vous gardez votre branche synchronisée avec la télécommande jusqu'à l'endroit où vous voulez qu'elle soit.
Nicolas C
0

Vous pouvez également, dans un autre répertoire:

  • git clone [votre référentiel]
  • Remplacez le répertoire .git de votre référentiel d'origine par le répertoire .git du référentiel que vous venez de cloner en ce moment.
  • git ajouter et git valider votre original
NunoSempere
la source