Comment «écraser», plutôt que «fusionner», une branche sur une autre branche dans Git?


257

J'ai deux branches, emailet staging. stagingest la dernière et je n'ai plus besoin des anciens changements de emailbranche, mais je ne veux pas les supprimer.

Je veux donc simplement vider tout le contenu de stagingdans emailafin qu'ils pointent tous deux vers le même commit. Est-ce possible?


Réponses:


196

Vous pouvez utiliser la stratégie de fusion «la nôtre»:

$ git checkout staging
$ git merge -s ours email # Merge branches, but use our branch head

26
J'ai essayé ça, et ça me semble à l'envers? Cela ne vide-t-il pas le contenu du courrier électronique dans la mise en scène et non l'inverse?
Max

27
@Max J'ai eu la même confusion et cela m'a causé beaucoup de problèmes. Vous devez exécuter cette commande à partir de la branche la plus récente (transfert), puis effectuer une fusion / RP normale avec votre ancienne branche (e-mail).
MrGlass

7
Pourquoi ;à la fin de chaque commande? Je l'ai fait sans ;et ça semble marcher. De plus, cette réponse est incomplète, la troisième étape consiste à extraire l'ancienne branche (e-mail), puis à fusionner à nouveau avec le transfert.
Rosdi Kasim

4
git rebase -s theirs <oldbranc> <newbranch> fonctionne également (peu importe la branche dans laquelle vous vous trouvez). Notez que dans le rebase, «leur» est en fait la nouvelle branche parce que «la nôtre» est la tête à laquelle nous appliquons actuellement les commits.
Rolf

4
@Rolf: mais le rebase supprimera les informations de fusion et aplatira l'historique. Pas nécessairement ce que vous recherchez. Ce n'est pas non plus une bonne idée, si vous travaillez avec une histoire déjà publiée.
knittl

99

Si vous voulez juste que les deux branches 'email' et 'staging' soient identiques, vous pouvez marquer la branche 'email', puis réinitialiser la branche 'email' sur celle 'staging':

$ git checkout email
$ git tag old-email-branch
$ git reset --hard staging

Vous pouvez également rebaser la branche 'staging' sur la branche 'email'. Mais le résultat contiendra la modification des deux branches.


1
vous voulez dire probablement git checkout, git checkn'existe pas à ma connaissance
knittl

4
Vous avez raison, j'ai tellement l'habitude de tabuler la fin de la commande git que j'écris toujours "git check <TAB>" pour écrire "git checkout"! Corrigée.
Sylvain Defresne

17
git reset casse le repo d'autres personnes qui ont cloné votre repo
Geoffrey De Smet

Je pense que c'est la bonne réponse. emailla tête de la branche doit simplement pointer vers le même chef staginget ils auront tous les deux les mêmes commits, la même histoire.
cicerocamargo

76

J'ai vu plusieurs réponses et c'est la seule procédure qui m'a permis de résoudre ce problème sans aucun conflit.

Si vous voulez toutes les modifications de branch_new dans branch_old, alors:

git checkout branch_new
git merge -s ours branch_old
git checkout branch_old
git merge branch_new

une fois ces quatre commandes appliquées, vous pouvez pousser le branch_old sans aucun problème


5
Votre réponse correspondait mieux à mon problème car je ne voulais pas réinitialiser le HEAD, indiquez simplement une préférence pour les fichiers les plus récents dans la branche la plus récente lors de la fusion des choses dans l'ancien, et cela a fonctionné sans problème! +1
poêles

J'ai poussé ma branche_nouvelle à distance après la "fusion de la nôtre", et cette méthode a fonctionné pour moi. Était-il nécessaire que je pousse? Ou aurait-il fonctionné sans? (Je n'étais pas sûr s'il utiliserait la branche locale ou la télécommande). Merci!
aspergillusOryzae

Pourquoi ne pouvez-vous pas simplement faire ce qui suit? git checkout branch_old git merge -s theirs branch_new Indice tiré de stackoverflow.com/questions/14275856/…
Ripu Daman

Il dit, n'a pas pu trouver la stratégie de fusion «la leur».
arango_86

Fonctionne parfaitement pour moi, a l'avantage de ne rien réinitialiser
Romain

68

Les autres réponses m'ont donné les bons indices, mais elles n'ont pas complètement aidé.

Voici ce qui a fonctionné pour moi:

$ git checkout email
$ git tag old-email-branch # This is optional
$ git reset --hard staging
$
$ # Using a custom commit message for the merge below
$ git merge -m 'Merge -s our where _ours_ is the branch staging' -s ours origin/email
$ git push origin email

Sans la quatrième étape de la fusion avec la nôtre, la poussée est considérée comme une mise à jour non rapide et sera rejetée (par GitHub).


Cela rend le message de fusion-validation incorrect, mais oui, cela fonctionne très bien.
cdunn2001

cdunn2001, je suis curieux. Quel était le message de fusion-validation que vous attendiez et comment cela a-t-il été gâché?
Shyam Habarakada

Il dit "Fusionner la branche de suivi à distance 'origine / e-mail' dans l'e-mail". Il ne mentionne pas de mise en scène. Mais ce n'est pas grave. Modifiez simplement le commit ou utilisez-le merge -m 'This is not my beautiful house.' -s ours origin/email.
cdunn2001

@ShyamHabarakada, je fais ce que vous dites et je reçois le problème de la mise à jour non rapide. car rien ne se passe quand je fais la 4ème étape.
kommradHomer

La 4ème étape vous oblige à utiliser l'origine / e-mail, cela ne fonctionne pas avec seulement les e-mails locaux.
Travis Reeder

45

Si vous êtes comme moi et que vous ne souhaitez pas gérer la fusion, vous pouvez effectuer les étapes ci-dessus, sauf utiliser la force au lieu de la fusion, car cela créera une trace de papier journal distrayante:

git checkout email
git reset --hard staging
git push origin email --force

Remarque: c'est uniquement si vous ne voulez VRAIMENT plus jamais revoir les informations contenues dans les e-mails.


1
git push origin email --force n'a pas fonctionné pour moi car les branches gauche de Step2 divergeaient. Donc, après l'étape 2, voici ce que j'ai fait: git reset origin / email puis git push
user3505394

2
C'est exactement ce qui a été demandé - "comment remplacer plutôt que fusionner". Devrait être accepté la réponse.
jozols

17

Je voulais fusionner deux branches pour que tout le contenu old_branchsoit mis à jour avec le contenu denew_branch

Pour moi, cela a fonctionné comme un charme:

$ git checkout new_branch
$ git merge -m 'merge message' -s ours origin/old_branch
$ git checkout old_branch
$ git merge new_branch
$ git push origin old_branch

10

Que diriez-vous:

git branch -D email
git checkout staging
git checkout -b email
git push origin email --force-with-lease

@emptywalls car il effectue une poussée forcée sans avertir l'utilisateur qu'il peut être rejeté par le serveur, ni expliquer pourquoi il est nécessaire. Cela dit, c'est une option viable pour un projet à un développeur
David Costa

@DavidCosta pourquoi cela serait-il rejeté par le serveur? il s'agit d'une simple suppression de branche d'e-mail et de copie de la mise en scène vers l'e-mail '... Je veux donc simplement vider tout le contenu de la' mise en scène 'dans' e-mail 'afin qu'ils pointent tous les deux vers le même commit' - c'est exactement ce qui se passe ici.
Arek S

@ArekS il peut être refusé par un hook côté serveur si la branche est définie comme "protégée", par exemple dans GitLab. Le problème est que si quelqu'un d'autre a dérivé sa branche par e-mail avant cette opération et essaie ensuite de pousser, les références ne correspondent plus (car certains commits ont tout simplement disparu)
David Costa

1
J'ai édité l'original de --force à --force-with-lease, qui fait l'affaire de manière non destructive.
frandroid

1
C'est le meilleur moyen si vous voulez simplement souffler une branche et la nettoyer à partir de la branche source.
Shane

6

D'autres réponses semblaient incomplètes.
J'ai essayé ci-dessous en entier, et cela a bien fonctionné.

REMARQUE:
1. Faites une copie de votre référentiel avant d'essayer ci-dessous, par sécurité.

Détails:
1. Tout le développement se produit dans la branche de développement
2. La branche qa est exactement la même copie de développement
3. De temps en temps, le code de développement doit être déplacé / écrasé dans la branche qa

nous devons donc écraser la branche qa, de la branche dev

Partie 1:
Avec les commandes ci-dessous, l'ancien qa a été mis à jour vers le nouveau dev:

git checkout dev
git merge -s ours qa
git checkout qa
git merge dev
git push

Le commentaire automatique pour la dernière poussée donne ci-dessous:

// Output:
//  *<MYNAME> Merge branch 'qa' into dev,*  

Ce commentaire est inversé, car la séquence ci-dessus est également inversée

Partie 2:

Ci-dessous sont inattendus, de nouveaux commits locaux en dev, les inutiles
donc, nous devons les jeter et les rendre intacts.

git checkout dev

// Output:
//  Switched to branch 'dev'  
//  Your branch is ahead of 'origin/dev' by 15 commits.  
//  (use "git push" to publish your local commits)


git reset --hard origin/dev  

//  Now we threw away the unexpected commits

Partie 3:
Vérifiez que tout est comme prévu:

git status  

// Output:
//  *On branch dev  
//  Your branch is up-to-date with 'origin/dev'.  
//  nothing to commit, working tree clean*  

C'est tout.
1. l'ancien qa est maintenant écrasé par le nouveau code de branche de développement
2. local est propre (origine distante / dev est intacte)


6

La façon la plus simple de le faire:

//the branch you want to overwrite
git checkout email 

//reset to the new branch
git reset --hard origin/staging

// push to remote
git push -f

Maintenant, la branche e-mail et la mise en scène sont les mêmes.


2
Avertissement: cela supprime tous les commits sur la emailbranche. C'est comme supprimer la emailbranche et la recréer à la tête de la stagingbranche.
Cameron Hudson

2
git checkout email
git merge -m "Making email same as staging disregarding any conflicts from email in the process" -s recursive -X theirs staging

1
Cette réponse aurait été plus claire pour moi si le commentaire avait été séparé du commentaire de fusion dans la commande. Expliquez brièvement ce que fait -X et comment il affecte cette fusion. Merci quand même.
M'a

@noelicus merci pour le commentaire et vous avez raison. Je pourrais éditer la réponse à l'avenir.
Willa

0

Celui-ci ne modifie pas la branche plus récente d'origine et vous donne la possibilité de faire d'autres modifications avant la validation finale.

git checkout new -b tmp
git merge -s ours old -m 'irrelevant'
git checkout old
git merge --squash tmp
git branch -D tmp
#do any other stuff you want
git add -A; git commit -m 'foo' #commit (or however you like)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.