Rebase un seul commit Git

116

Existe-t-il un moyen de rebaser un seul commit d'une branche vers une autre branche?

J'ai cette structure de branche:

-- -- -- -- -- (Master)
            \
              -- -- -- -- -- XX (Feature-branch)

Tout ce que je veux faire, c'est rebaser le dernier commit de Feature-branchsur master et annuler Feature-branchun commit.

-- -- -- -- -- XX (Master)
            \
              -- -- -- -- -- (Feature-branch)

Comment je fais ça?

Kevin Meyer
la source
3
Si vous pouvez rebaser un certain nombre de commits, pourquoi demandez-vous de rebaser un seul? Si je pouvais poser des questions dans SO, je demanderais quelle est la différence entre le rebasage (un seul commit) et le cherry-picking.
Val
9
Parce que je ne savais pas que le cherry-picking existait, et je fais "Faff about on branch", "Get request for fix on different branch", "fix it", "Commit to bad branch", "D'OH!" assez que poser la question était utile.
Kevin Meyer

Réponses:

116

Vous pouvez choisir XX à maîtriser.

git checkout master
git cherry-pick <commit ID of XX>

Et supprimez le dernier commit de la branche de fonctionnalité avec git reset.

git checkout Feature-branch
git reset --hard HEAD^
tewe
la source
64
Comment une question spécifiquement appelée 'git rebase ...' peut-elle avoir la réponse acceptée qui contient un choix de cerise, qui est un concept totalement différent et parfois considéré en soi comme impur?
Bondax
1
Je ne sais pas si cela est pertinent, mais le commit que je voulais rebaser contenait certains fichiers qui avaient été déplacés et les cherry-pickfaisait apparaître comme s'ils avaient été supprimés de l'ancien emplacement et créés au nouvel emplacement. Je suppose que rebase aurait pris soin de cela, mais maintenant j'ai poussé en amont, donc je ne peux pas le tester. Dans tous les cas, méfiez-vous si vous avez une situation similaire.
waldyrious
Remarque: pour pousser les modifications Feature-branchvers l'origine, vous devrez le faire git push -f origin Feature-branchcar votre Feature-branchest maintenant considéré comme un commit derrière le origin/Feature-branch.
jojo
1
Quelle est la différence pratique entre cette solution et celle de CharlesB ?
Lii
96
git rebase --onto master branch~1 branch 

Cela dit "rebase la plage de commits entre la dernière branche avant et la branche (c'est-à-dire XX commit) sur la pointe de la branche principale"

Une fois que cette branchastuce d' opération est déplacée lors de la validation XX, vous voulez la réinitialiser avec

git checkout branch
git reset --hard branch@{1}^

Qui dit "réinitialiser la pointe de la branche au commit avant son état précédent"

Un choix de cerises est donc une solution plus simple ...

CharlesB
la source
5
Cela ne semble pas fonctionner pour moi, je perds les commits avant XX et la branche est rebasée en master avec un seul commit, mais je ne l'ai jamais utilisé --ontoauparavant, donc je fais peut-être quelque chose de mal. BTW l'OP a dit rebase, mais il semble qu'il veuille faire un choix de cerise.
tewe
1
mon erreur, rebase déplace effectivement la branche sur master, elle doit être réinitialisée
CharlesB
1
Quelle est la différence pratique entre cette solution et celle de tewe ?
Lii
1
@Lii le seul que je peux voir, c'est qu'il utilise 3 étapes au lieu de 4
CharlesB
52

C'est assez simple à faire en fait. La solution est de faire un rebase interactif et de «supprimer» tous les commits que vous ne voulez pas inclure dans le rebase.

git rebase -i <target_branch>target_branchest la branche sur laquelle vous souhaitez rebaser

Ensuite, vous éditerez le fichier qui est ouvert et pickles commits que vous voulez et drop(ou den bref) tous les commits que vous ne voulez pas apporter.

hrdwdmrbl
la source
6
L'OMI est une bien meilleure solution, et elle répond en fait à la question.
GabrielOshiro
Cela devrait être la solution acceptée étant donné son caractère général, intuitif et court.
Pablo Arias
1

La réponse de @Charles est correcte. Quoi qu'il en soit, j'ai fini par l'utiliser tant de fois, surtout pour rebaser une configuration spécifique sur un projet

  * a8f9182 (HEAD -> production) configuration de production
  | * configuration de préproduction daa18b7 (pré)
  | /  
  | * Configuration locale d365f5f (locale)
  | /  
  * 27d2835 (dev) nouvelle fonctionnalité étonnante qui sauvera le monde
* | 56d2467 (maître) état de l'art ennuyeux pour le projet
| /

que je crée une nouvelle commande pour cela:

$ cat ~ / bin / git-rebaseshot 
COMMIT = 1 $
DEST = $ {2: -HEAD}
git rebase $ {COMMIT} ^ $ {COMMIT} --onto $ DEST

normalement, vous voulez compléter automatiquement les noms de branche pour cette commande, alors ajoutez-le en source de cette fonction (en ajoutant à .bashrc ou .profile):

_git_rebaseshot () 
{ 
    __gitcomp_nl "$ (__ git_refs)"
}

git autocomplete le recherchera

vous pouvez utiliser cette commande comme ceci:

# rebase config on prepro on actual HEAD
$ git rebaseshot prepro 
# rebase config on local onto dev
$ git rebaseshot local dev
# rebase production config on master
$ git rebaseshot pro master

Lorsque vous divisez correctement les entités, les possibilités sont infinies.

* a8f9182 (HEAD -> postgres) Configuration BBDD
* a8f9182 (local) configuration locale
* a8f9182 (débogage) configuration du niveau de journalisation
* nouvelle fonctionnalité a8f9182 (dev)
|

Je suppose que c'est ce que couette gens aiment faire.

cette commande fonctionnera de toute façon avec tout sha / ref que vous fournissez:

$ git rebaseshot <Feature branch> master
$ git rebaseshot <commit of XX> master
Albfan
la source
//, Pouvez-vous créer un lien vers un projet où nous pouvons voir cela en action?
Nathan Basanese
De par sa nature, les succursales disponibles pour rebaseshot ne sont pas engagées en dehors du repo local. Créez simplement plusieurs branches au-dessus du maître (niveau de journalisation, connexion à la base de données, configuration) et utilisez la commande entre elles. Est clair pour voir l'effet.
albfan
//, j'ai rencontré des problèmes. Je vais essayer à nouveau.
Nathan Basanese
0

Voici une autre option:

  1. Assurez-vous d'avoir une télécommande avec une copie de la branche de fonctionnalités
  2. Supprimer la branche d'objets locaux
  3. Créez et récupérez une nouvelle branche avec le même nom que l'ancienne branche de fonctionnalité que vous venez de supprimer du maître
  4. Choisissez en cerise le commit dans la copie distante de la branche de fonctionnalité souhaitée.

Les commandes ressemblent à:

git checkout Feature-branch
git push -u origin HEAD
git checkout master
git branch -D Feature-branch
git checkout -b Feature-branch
git cherry-pick HASH-OF-XX

Ce n'est pas une commande de rebase non, mais c'est un rebase dans l'esprit.

cdmo
la source