déplacer les modifications validées (mais non poussées) vers une nouvelle branche après le tirage

460

J'ai fait pas mal de travail ("Votre branche est en avance sur 'origine / master' par 37 commits.") Qui aurait vraiment dû aller dans sa propre branche plutôt que dans master. Ces commits n'existent que sur ma machine locale et n'ont pas été poussés vers origin, mais la situation est quelque peu compliquée dans la mesure où d'autres développeurs ont poussé origin/masteret j'ai retiré ces changements.

Comment déplacer rétroactivement mes 37 commits locaux dans une nouvelle succursale? Sur la base des documents, il semble que cela devrait git rebase --onto my-new-branch masterou ...origin/masterdevrait le faire, mais les deux me donnent simplement l'erreur "fatal: besoin d'une seule révision". man git-rebasene dit rien sur la fourniture d'une révision rebaseet ses exemples ne le font pas, donc je ne sais pas comment résoudre cette erreur.

(Notez qu'il ne s'agit pas d' un doublon de Déplacer un travail existant non engagé vers une nouvelle branche dans Git ou Comment fusionner mes modifications locales non validées dans une autre branche Git? Car ces questions concernent les modifications non validées dans l'arborescence de travail locale, pas les modifications qui ont été engagé localement.)

Dave Sherohman
la source
Découvrez cette solution . Semble être facile et propre.
Tony
Découvrez cette solution . Semble être facile et propre.
Tony

Réponses:

518

Cela ne devrait pas poser de problème, car vous n'avez encore poussé vos validations nulle part ailleurs et vous êtes libre de réécrire l'historique de votre branche par la suite origin/master. Je voudrais d'abord exécuter un git fetch originpour m'assurer que origin/masterc'est à jour. En supposant que vous êtes actuellement connecté master, vous devriez pouvoir:

git rebase origin/master

... qui rejouera toutes vos validations qui ne sont pas origin/masterenregistrées origin/master. L'action par défaut de rebase est d'ignorer les validations de fusion (par exemple celles que vous avez git pullprobablement introduites) et il essaiera simplement d'appliquer le patch introduit par chacune de vos validations origin/master. (Vous devrez peut-être résoudre certains conflits en cours de route.) Ensuite, vous pouvez créer votre nouvelle branche en fonction du résultat:

git branch new-work

... puis réinitialisez votre masterdos à origin/master:

# Use with care - make sure "git status" is clean and you're still on master:
git reset --hard origin/master

Quand vous faites ce genre de manipulation avec des branches git branch, git resetetc. Je trouve utile de regarder souvent au commettras graphique avec gitk --allou un outil similaire, juste pour vérifier que je comprends tous les différents refs pointent.

Alternativement, vous pourriez avoir simplement créé une branche de sujet en fonction de l'endroit où se trouve votre maître en premier lieu ( git branch new-work-including-merges), puis réinitialiser mastercomme ci-dessus. Cependant, étant donné que votre branche de sujet inclura des fusions de origin/masteret que vous n'avez pas encore poussé vos modifications, je vous suggère de faire un rebase afin que l'historique soit plus ordonné. (De plus, lorsque vous fusionnerez éventuellement votre branche de sujet en maître, les changements seront plus évidents.)

Mark Longair
la source
8
@Olie: Non, la réponse est correcte selon les hypothèses de la question et celles que j'ai énoncées en haut de la réponse. Les validations qui devraient être sur une nouvelle branche distincte sont déjà dans master; le rebase réécrit la masterbranche de sorte que les nouveaux validations soient linéairement au-dessus de origin/master, puis git branch new-workcrée une new-workbranche pointant à la pointe de master(la branche actuelle) sans basculer la branche actuelle vers new-work. new-workContient donc maintenant tous les nouveaux commits. Ensuite, la réinitialisation masterramène (encore ) la branche actuelle à origin/master.
Mark Longair
1
@Quintesse: Je suis vraiment désolé si vous avez perdu du travail, mais je suis sûr que cette réponse est correcte pour la situation décrite par l'interrogateur d'origine. (Je viens de répondre aux remarques d'Olie, je l'espère, en clarifiant.) Quoi qu'il en soit, juste au cas où cela aiderait à récupérer votre travail, je dois dire que si votre travail a été commis au cours des derniers jours (l'une des hypothèses de cette question et réponse) ), vous devriez pouvoir le récupérer facilement via le git reflog.
Mark Longair
5
@Olie: peut-être une meilleure façon d'expliquer: les branches dans git sont comme des étiquettes qui pointent vers un commit particulier; ils sont automatiquement déplacés vers de nouveaux commits si vous les créez sur cette branche ou si vous pouvez les déplacer de git resetdifférentes manières. Le git branch new-workdit simplement "créer une branche pointant sur ce commit pendant que je reste sur ma branche actuelle (qui est master dans ce cas)". Il n'est donc pas nécessaire d'avoir une commande qui déplace les validations de master vers la nouvelle branche - vous créez simplement une nouvelle branche là-bas et lorsque vous réinitialisez master, la nouvelle branche reste là où se trouvait master
Mark Longair
1
un peu tard pour la fête, mais @Olie, ce n'est pas parce que le statut git lorsque sur la nouvelle branche n'affiche pas les commits avant master qu'ils ne sont pas réellement là (en supposant que c'est pourquoi vous étiez inquiet). Essayez de pousser la nouvelle branche vers l'origine: vous verrez que les commits sont là
Félix Gagnon-Grenier
2
@ FélixGagnon-Grenier, ne vous inquiétez pas des "retards" - il y a toujours des gens qui consultent de vieilles questions et chaque clarification aide. Merci! :)
Olie
148

Si vous avez un faible nombre de commits et que vous ne vous souciez pas de les combiner en un méga-commit, cela fonctionne bien et n'est pas aussi effrayant que de le faire git rebase:

désinstaller les fichiers (remplacez 1 par # de commits)

git reset --soft HEAD~1

créer une nouvelle branche

git checkout -b NewBranchName

ajouter les modifications

git add -A

faire un commit

git commit -m "Whatever"
Stachu
la source
5
Pour afficher un graphique facile à comprendre, veuillez utiliser git log --all --decorate --oneline --graph.
EliuX
Hé @EliuX - Je manque la pertinence ici. Pouvez-vous vous étendre?
Stachu
C'est quelque chose d'utile pour vérifier si vous avez obtenu le résultat souhaité dans ce que vous avez fait
EliuX
4
Merci!! c'est une solution très simple et cela a parfaitement fonctionné !!
Chris Sim
91

Je suis resté avec le même problème. J'ai trouvé la solution la plus simple que j'aime partager.

1) Créez une nouvelle branche avec vos modifications.

git checkout -b mybranch

2) (Facultatif) Poussez le nouveau code de branche sur le serveur distant.

git push origin mybranch

3) Revenez à la succursale principale.

git checkout master

4) Réinitialisez le code de branche maître avec le serveur distant et supprimez la validation locale.

git reset --hard origin/master
NiRmaL
la source
10
C'est vraiment le moyen le plus simple
dhilt
4
Vous pouvez laisser de côté l'étape 2. Je suppose que dans le temps écoulé depuis la première réponse, git a changé et cette procédure n'était pas autorisée auparavant.
Sebastian
C'est la meilleure réponse à mon avis.
Macindows
1
Cette réponse doit se déplacer vers le haut. Je vous remercie.
Amit
27

Une autre façon de supposer que branch1 - est une branche avec des changements validés branch2 - est une branche souhaitable

git fetch && git checkout branch1
git log

sélectionnez les ID de validation que vous devez déplacer

git fetch && git checkout branch2
git cherry-pick commit_id_first..commit_id_last
git push

Maintenant, annulez les validations non poussées de la branche initiale

git fetch && git checkout branch1
git reset --soft HEAD~1
Andriy
la source
5
Cherry-pick est vraiment la meilleure commande "copier / déplacer un seul commit", en particulier. quand l'histoire est un bagage pour vous.
John Neuhaus
C'est jusqu'à présent la réponse la plus pratique à la question. Merci pour la commande!
Farah
pouvez-vous mettre à jour votre dernier commentaire où 1 ou n est le nombre de validations non poussées? C'est toujours une très bonne solution pour cette question.
chAlexey
9

Alternativement, juste après vous être engagé dans la mauvaise branche, procédez comme suit:

  1. git log
  2. git diff {previous to last commit} {latest commit} > your_changes.patch
  3. git reset --hard origin/{your current branch}
  4. git checkout -b {new branch}
  5. git apply your_changes.patch

Je peux imaginer qu'il existe une approche plus simple pour les étapes un et deux.

Andreas B
la source
6

Qu'en est-il de:

  1. Branche de l'actuel HEAD.
  2. Assurez-vous que vous êtes maître , pas votre nouvelle branche.
  3. git reset revenir au dernier commit avant de commencer à apporter des modifications.
  4. git pull pour ré-extraire uniquement les modifications à distance que vous avez supprimées avec la réinitialisation.

Ou cela explosera-t-il lorsque vous tenterez de refusionner la branche?

Tim Keating
la source
2
Ah, c'est essentiellement l'option B décrite par @ Mark-Longair ci-dessus
Tim Keating
2

Voici une manière beaucoup plus simple:

  1. Créer une nouvelle branche

  2. Sur votre nouvelle branche, faites un git merge master- cela fusionnera vos modifications validées (non poussées) dans votre nouvelle branche

  3. Supprimez votre branche principale locale git branch -D masterUtilisez -Dplutôt que -dparce que vous souhaitez forcer la suppression de la branche.

  4. git fetchFaites juste un sur votre branche principale et faites un git pullsur votre branche principale pour vous assurer d'avoir le dernier code de vos équipes.

A Kok
la source
1

Une approche plus simple, que j'ai utilisée (en supposant que vous vouliez déplacer 4 commits):

git format-patch HEAD~4

(Regardez dans le répertoire à partir duquel vous avez exécuté la dernière commande pour les 4 .patchfichiers)

git reset HEAD~4 --hard

git checkout -b tmp/my-new-branch

Alors:

git apply /path/to/patch.patch

Dans l'ordre que vous vouliez.

user1429980
la source
0
  1. Commander une nouvelle copie de vos sources

    git clone ........

  2. Créer une succursale à partir de la position souhaitée

    git checkout {position} git checkout -b {branch-name}

  3. Ajouter un référentiel distant

    git remote add shared ../{original sources location}.git

  4. Obtenez des sources distantes

    git fetch shared

  5. Commander la branche souhaitée

    git checkout {branch-name}

  6. Fusionner les sources

    git merge shared/{original branch from shared repository}

Sergey Kabashnyuk
la source
0

Pour moi, c'était la meilleure façon:

  1. Vérifier les modifications et les conflits de fusion git fetch
  2. Créer une nouvelle succursale git branch my-changeset pousser vers la télécommande
  3. Passer en amont à une nouvelle branche créée git master -u upstream-branch remotes/origin/my-changes
  4. Poussez vos commits vers la nouvelle branche en amont.
  5. Revenir au précédent en amont git branch master --set-upstream-to remotes/origin/master
Sébastien
la source