Faire de la branche Git actuelle une branche master

1657

J'ai un référentiel dans Git. J'ai créé une branche, puis j'ai apporté des modifications à la fois au maître et à la branche.

Ensuite, des dizaines de commits plus tard, j'ai réalisé que la branche est dans un bien meilleur état que le maître, donc je veux que la branche "devienne" le maître et ignore les changements sur le maître.

Je ne peux pas le fusionner, car je ne veux pas conserver les modifications sur master. Que devrais-je faire?

Extra : Dans ce cas, le «vieux» maître a déjà été push-ed dans un autre référentiel tel que GitHub. Comment cela change-t-il les choses?

Karel Bílek
la source
2
Vérifiez les réponses à la question très similaire stackoverflow.com/q/2862590/151641
mloskot
4
J'ai eu le même problème, mais j'ai simplement supprimé le maître et renommé une autre branche en maître: stackoverflow.com/a/14518201/189673
jayarjo
10
@jayarjo, vous devriez éviter cela si vous le pouvez, car cela réécrira l'historique et causera des problèmes à tout le monde lors de la prochaine tentative d'extraction du maître.
joelittlejohn
3
C'est pourquoi j'aime la réponse de @Jefromi. Aucune déconstruction de l'histoire des archives n'est en cours.
froggythefrog

Réponses:

2134

Le problème avec les deux autres réponses est que le nouveau maître n'a pas l'ancien maître comme ancêtre, donc quand vous le poussez, tout le monde sera foiré. Voici ce que vous voulez faire:

git checkout better_branch
git merge --strategy=ours master    # keep the content of this branch, but record a merge
git checkout master
git merge better_branch             # fast-forward master up to the merge

Si vous souhaitez que votre historique soit un peu plus clair, je vous recommande d'ajouter des informations au message de validation de fusion pour clarifier ce que vous avez fait. Remplacez la deuxième ligne par:

git merge --strategy=ours --no-commit master
git commit          # add information to the template merge message
Cascabel
la source
25
Remarque sur les "stratégies" de fusion de git: --strategy=oursest différent de --strategy=recursive -Xours. C'est-à-dire que "la nôtre" peut être une stratégie en soi (le résultat sera la branche actuelle quoi qu'il arrive), ou passé en option à la stratégie "récursive" (apportez les changements d'autres branches, et préférez automatiquement les changements de la branche actuelle en cas de conflit) ).
Kelvin
5
J'ai dû faire la deuxième ligne git merge --strategy=ours master -m "new master"pour que ça marche.
incandescentman
5
@Johsm C'est exactement ce dont parle la première phrase de ma réponse. Si vous faites cela, le nouveau maître n'aura pas la même histoire que l'ancien maître, ce qui est très mauvais si vous voulez pousser / tirer. Vous devez avoir une ascendance partagée pour que cela fonctionne correctement; si au lieu de cela vous faites ce que vous dites, alors lorsque vous essayez de le pousser, il échouera simplement à moins que vous ne le forciez (parce que c'est mauvais et qu'il essaie de vous arrêter), et si vous le forcez, alors toute personne qui tire par la suite tentera de fusionner l'ancien maître et le nouveau maître, qui sera probablement une épave de train.
Cascabel
4
Si l'éditeur vi pendant la fusion apparaît, tapez: w (pour l'enregistrement): q (pour quitter vi)
Tomas Kubes
9
Cette réponse fonctionne très bien. Je voulais juste ajouter (pour les personnes qui peuvent être nouvelles ou incertaines) que vous devrez faire un git pushdroit après cela si vous voulez que votre code soit poussé à distance. Vous pouvez voir un avertissement comme celui- Your branch is ahead of 'origin/master' by 50 commits.ci est attendu. Poussez-le! : D
chapeljuice
388

Assurez-vous que tout est poussé vers votre référentiel distant (GitHub):

git checkout master

Remplacez "master" par "better_branch":

git reset --hard better_branch

Forcez le push vers votre référentiel distant:

git push -f origin master
Brandon Howard
la source
81
C'est probablement la réponse que la plupart des gens recherchent. Toutes les autres réponses avec la fusion de stratégie BS ne remplacent pas entièrement la branche. Cela a fait tout ce que je voulais, simplement écraser la branche et pousser pour la forcer.
Gubatron
31
bien que ce soit en effet ce que beaucoup recherchent, il convient de noter que toutes les autres copies locales du référentiel devront la git reset --hard origin/masterprochaine fois qu'elles veulent être extraites, sinon git essaiera de fusionner les modifications dans leur (maintenant) divergence locale. Les dangers de ceci sont expliqués plus dans cette réponse
7yl4r
3
veuillez également noter que vous devez être autorisé à forcer l'envoi au référentiel - par exemple, dans un environnement professionnel, cela ne fonctionnera pas
inetphantom
L'avantage ici peut également être un inconvénient selon ce que les gens veulent. Si vous voulez aller jusqu'à remplacer l'histoire du maître par l'histoire de l'autre branche, c'est votre réponse.
b15
75

Edit: Vous n'avez pas dit que vous aviez poussé à un repo public! Cela fait toute une différence.

Il y a deux façons, la voie "sale" et la voie "propre". Supposons que votre branche soit nommée new-master. C'est la voie propre:

git checkout new-master
git branch -m master old-master
git branch -m new-master master
# And don't do this part.  Just don't.  But if you want to...
# git branch -d --force old-master

Cela fera changer les fichiers de configuration pour correspondre aux branches renommées.

Vous pouvez également le faire de manière sale, qui ne mettra pas à jour les fichiers de configuration. C'est un peu ce qui se passe sous le capot de ce qui précède ...

mv -i .git/refs/new-master .git/refs/master
git checkout master
Dietrich Epp
la source
2
Je vous remercie. Encore une question. Je le pousse vers github. Que se passera-t-il là-bas, si je fais cela?
Karel Bílek
3
@Karel: Cela va créer un peu de gâchis pour les autres utilisateurs; ils devront réinitialiser leur maître sur le maître github. Si vous voulez éviter de leur causer des ennuis, jetez un œil à ma réponse.
Cascabel
6
@Dietrick Epp: Je ne sais pas si c'est une bonne idée de suggérer même la voie sale. Cela va gâcher le suivi à distance, les reflogs ... je ne vois aucune raison pour laquelle vous le feriez jamais.
Cascabel
2
Ah, c'est un bon point. Vous pouvez avoir les deux, bien que: git branch old-master master; git branch -f master new-master. Créez une nouvelle branche de sauvegarde, puis déplacez directement le maître vers le nouveau maître. (Et désolé d'avoir mal orthographié votre nom, je viens de le remarquer)
Cascabel
2
@FakeName Je n'ai pas conclu qu'il n'y avait aucune raison de le faire, juste qu'il n'y a aucune raison de le faire de la mauvaise façon . Vous pouvez le faire en utilisant des commandes normales (comme dans mon commentaire précédent) et obtenir le même résultat, sauf avec des reflogs intacts et aucune chance de bouger les choses. Et il est garanti que cela fonctionne, car vous ne cachez pas les détails de mise en œuvre.
Cascabel
46

Renommez la branche masteren:

git branch -M branch_name master
Alan Haggai Alavi
la source
11
Malheureusement, git ne suit pas les renommages de branches, donc si vous avez déjà poussé votre dépôt vers une télécommande et que d'autres ont des changements locaux sur leur ancienne branche principale locale, ils auront des problèmes.
thSoft
y a-t-il une différence entre cela et git checkout master&&git reset --hard better_branch?
wotanii
26

D'après ce que je comprends, vous pouvez brancher la branche actuelle dans une branche existante. En substance, cela remplacera mastertout ce que vous avez dans la branche actuelle:

git branch -f master HEAD

Une fois que vous avez fait cela, vous pouvez normalement pousser votre masterbranche locale , nécessitant éventuellement le paramètre force ici également:

git push -f origin master

Pas de fusion, pas de longues commandes. Simplement branchet push- mais, oui, cela réécrira l'historique de la masterbranche, donc si vous travaillez en équipe, vous devez savoir ce que vous faites.




Alternativement, j'ai trouvé que vous pouvez pousser n'importe quelle branche vers n'importe quelle branche distante, donc:

# This will force push the current branch to the remote master
git push -f origin HEAD:master

# Switch current branch to master
git checkout master

# Reset the local master branch to what's on the remote
git reset --hard origin/master
fregante
la source
Très simple et a parfaitement fonctionné! Deux commandes git simples et faciles à comprendre. Mon dépôt git est enregistré et semble maintenant super propre. Merci!
thehelix
16

J'ai trouvé la réponse que je voulais dans le blog Remplacez la branche principale par une autre branche dans git :

git checkout feature_branch
git merge -s ours --no-commit master
git commit      # Add a message regarding the replacement that you just did
git checkout master
git merge feature_branch

C'est essentiellement la même chose que la réponse de Cascabel . Sauf que l '"option" qu'il a ajoutée en dessous de sa solution est déjà intégrée dans mon bloc de code principal.

C'est plus facile à trouver de cette façon.

J'ajoute cela comme une nouvelle réponse, car si j'ai besoin de cette solution plus tard, je veux avoir tout le code que je vais utiliser dans un bloc de code.

Dans le cas contraire, je copier-coller, puis lire les détails ci - dessous pour voir la ligne que je devrais avoir changé - après avoir déjà exécutaient.

SherylHohman
la source
14

Les solutions données ici (renommer la branche en 'master') n'insistent pas sur les conséquences pour le dépôt distant (GitHub):

  • si vous n'avez rien poussé depuis la création de cette branche, vous pouvez la renommer et la pousser sans aucun problème.
  • si vous aviez push master sur GitHub, vous devrez 'git push -f' la nouvelle branche: vous ne pouvez plus pousser en mode avance rapide .
    -F
    --Obliger

Habituellement, la commande refuse de mettre à jour une référence distante qui n'est pas un ancêtre de la référence locale utilisée pour la remplacer. Ce drapeau désactive la vérification. Cela peut entraîner la perte de validations du référentiel distant; utilisez-le avec précaution.

Si d'autres ont déjà retiré votre référentiel, ils ne pourront pas extraire ce nouvel historique de maître sans remplacer leur propre maître par cette nouvelle branche principale de GitHub (ou gérer de nombreuses fusions).
Il existe des alternatives à git push --force pour les dépôts publics .
La réponse de Jefromi (fusionner les bons changements de retour au maître d'origine) est l'un d'entre eux.

VonC
la source
14

J'ai trouvé que cette méthode simple fonctionnait le mieux. Il ne réécrit pas l'historique et tous les enregistrements précédents de la branche seront ajoutés au maître. Rien n'est perdu et vous pouvez voir clairement ce qui s'est passé dans le journal de validation.

Objectif: faire de l'état actuel de la "branche" le "maître"

Travailler sur une branche, valider et pousser vos modifications pour vous assurer que vos référentiels locaux et distants sont à jour:

git checkout master      # Set local repository to master
git reset --hard branch  # Force working tree and index to branch
git push origin master    # Update remote repository

Après cela, votre maître sera l'état exact de votre dernière validation de branche et votre journal de validation maître affichera tous les enregistrements de la branche.

Mark Dietel
la source
10

On peut également extraire tous les fichiers de l'autre branche dans master:

git checkout master
git checkout better_branch -- .

puis validez toutes les modifications.

user2064284
la source
5

Pour ajouter à la réponse de Jefromi, si vous ne voulez pas placer une fusion vide de sens dans l'historique de la sourcebranche, vous pouvez créer une branche temporaire pour la oursfusion, puis la jeter:

git checkout <source>
git checkout -b temp            # temporary branch for merge
git merge -s ours <target>      # create merge commit with contents of <source>
git checkout <target>           # fast forward <target> to merge commit
git merge temp                  # ...
git branch -d temp              # throw temporary branch away

De cette façon, le commit de fusion n'existera que dans l'historique de la targetbranche.

Alternativement, si vous ne voulez pas créer de fusion du tout, vous pouvez simplement récupérer le contenu de sourceet les utiliser pour un nouveau commit sur target:

git checkout <source>                          # fill index with contents of <source>
git symbolic-ref HEAD <target>                 # tell git we're committing on <target>
git commit -m "Setting contents to <source>"   # make an ordinary commit with the contents of <source>
staafl
la source
3

Pour moi, je voulais que mon devl soit de retour au maître après qu'il était en avance.

Pendant le développement:

git checkout master
git pull

git checkout develop
git pull

git reset --hard origin/master
git push -f
Braden Borman
la source
2

Ma façon de faire est la suivante

#Backup branch
git checkout -b master_backup
git push origin master_backup
git checkout master
#Hard Reset master branch to the last common commit
git reset --hard e8c8597
#Merge
git merge develop
ar-g
la source
2

Si vous utilisez eGit dans Eclipse :

  • Faites un clic droit sur le nœud du projet.
  • Choisissez Équipe → puis Avancé → puis Renommer la branche
  • Développez ensuite le suivi à distance dossier de .
  • Choisissez la branche avec le mauvais nom, puis cliquez sur le bouton renommer, renommez-la en quelque soit le nouveau nom.
  • Choisissez le nouveau maître, puis renommez-le en maître.
Junchen Liu
la source
Je l'ai fait mais je ne sais pas si cela a fonctionné. Sur github, rien n'a changé mais sur les extensions git, je peux voir que la branche a été renommée.
Pramod
0

Les étapes suivantes sont effectuées dans le navigateur Git alimenté par Atlassian (serveur Bitbucket)

Faire {current-branch} comme master

  1. Faire une branche avec master et nommez-la «master-duplicate».
  2. Faites une branche de {branche-actuelle} et nommez-la "{branche-courante} -copie".
  3. Dans le paramètre du référentiel (Bitbucket), changez «Branche par défaut» pour pointer sur «maître-dupliqué» (sans cette étape, vous ne pourrez pas supprimer le maître - «À l'étape suivante»).
  4. Supprimer la branche "master" - J'ai fait cette étape depuis l'arborescence source (vous pouvez le faire depuis le navigateur CLI ou Git)
  5. Renommez «{current-branch}» en «master» et poussez vers le référentiel (cela créera une nouvelle branche «master» toujours «{current-branch}» existera).
  6. Dans les paramètres du référentiel, modifiez «Branche par défaut» pour pointer sur «maître».
Purushothaman
la source