Renommer la branche principale pour les référentiels Git locaux et distants

821

J'ai la branche masterqui suit la branche distante origin/master.

Je veux les renommer master-oldlocalement et sur la télécommande. Est-ce possible?

Pour les autres utilisateurs qui ont suivi origin/master(et qui ont toujours mis à jour leur masterbranche locale via git pull), que se passerait-il après avoir renommé la branche distante?
Est-ce que cela git pullfonctionnerait encore ou lancerait-il une erreur qu'il ne pourrait plus trouver origin/master?

Ensuite, plus loin, je veux créer une nouvelle masterbranche (à la fois localement et à distance). Encore une fois, après avoir fait cela, que se passerait-il maintenant si les autres utilisateurs le faisaient git pull?

Je suppose que tout cela entraînerait beaucoup de problèmes. Existe-t-il un moyen propre d'obtenir ce que je veux? Ou devrais-je simplement laisser mastertel quel et créer une nouvelle branche master-newet y travailler plus loin?

Albert
la source
2
La recette donnée dans la réponse acceptée ne s'applique à une branche d'un nom, mais les mises en garde (comme indiqué) ne sont pas, en raison de la (par défaut) rôle particulier du maître branche dans Git.
kynan
3
@kynan: Je pense que je ne comprends pas. Quelles mises en garde s'appliquent au master et ne s'appliquent pas aux autres branches? S'il s'agit d'une branche nommée xy et que d'autres personnes ont suivi cette branche, en quoi cela serait-il différent?
Albert
4
La mise en garde que vous ne pouvez pas normalement supprimer le maître distant. Cela ne s'applique pas à la réponse d'Aristote, alors vous voudrez peut-être marquer cela comme la réponse acceptée. Vous avez raison, tout git push -faffecte la capacité pullde n'importe quelle branche de suivi à distance.
kynan
vous pouvez créer une nouvelle branche master-oldqui pointe vers le même commit que la masterbranche précédente . Ensuite, vous pouvez remplacer la masterbranche avec vos nouvelles modifications en effectuant un mergeavec la oursstratégie. La fusion fonctionne lorsque la télécommande n'autorise pas les modifications non rapides. Cela signifie également que les autres utilisateurs n'auront pas de mises à jour forcées.
dnozay
1
@kynan mastern'est spécial que tant qu'il s'agit de la seule branche existante. Dès que vous en avez plusieurs, toutes les branches sont sur un pied d'égalité.
jub0bs

Réponses:

615

La chose la plus proche du changement de nom est la suppression puis la recréation sur la télécommande. Par exemple:

git branch -m master master-old
git push remote :master         # delete master
git push remote master-old      # create master-old on remote

git checkout -b master some-ref # create a new local master
git push remote master          # create master on remote

Cependant, cela comporte de nombreuses mises en garde. Tout d'abord, aucun retrait existant ne connaîtra le changement de nom - git n'essaie pas de suivre les renommages des branches. Si le nouveau mastern'existe pas encore, git pull sortira en erreur. Si le nouveau mastera été créé. la traction tentera de fusionner masteret master-old. C'est donc généralement une mauvaise idée, sauf si vous avez la coopération de tous ceux qui ont déjà vérifié le référentiel.

Remarque: les versions plus récentes de git ne vous permettront pas de supprimer la branche principale à distance par défaut. Vous pouvez remplacer cela en définissant la receive.denyDeleteCurrentvaleur de configuration sur warnou ignoresur le référentiel distant . Sinon, si vous êtes prêt à créer un nouveau master immédiatement, sautez l' git push remote :masterétape et passez --forceà l' git push remote masterétape. Notez que si vous ne pouvez pas modifier la configuration de la télécommande, vous ne pourrez pas supprimer complètement la branche principale!

Cette mise en garde ne s'applique qu'à la branche actuelle (généralement la masterbranche); toute autre branche peut être supprimée et recréée comme ci-dessus.

bdonlan
la source
2
les branches sont juste une paire (nom, hachage) - rien de plus, rien de moins. Il y a le reflog sur les branches, mais il n'est jamais exposé aux clients distants.
bdonlan
122
Je créerais master-old sur remote avant de supprimer master sur remote. Je suis juste paranoïaque.
Adam Dymitruk
6
La réponse d'Aristote ci-dessous vous permet de le faire sans supprimer le maître, donc je pense que c'est préférable.
Clay Bridges
13
il serait clair et sûr si vous pouvez utiliser new-branch-nameet old-branch-nameau lieu de master/ master-old, c'est donc un problème général.
Jaider
2
Si la branche supprimée (ici: master) n'est pas référencée par d'autres branches, git risque de récupérer tous les commits sur cette ... eh bien ... "branche". - Certaines commandes git porcelain déclenchent un ramasse-miettes. - Par conséquent: créez d'abord le nouveau nom (pointant vers le même commit), puis supprimez l'ancien nom.
Robert Siemer
257

En supposant que vous êtes actuellement sur master:

git push origin master:master-old        # 1
git branch master-old origin/master-old  # 2
git reset --hard $new_master_commit      # 3
git push -f origin                       # 4
  1. Créez d'abord une master-oldbranche dans le originréférentiel, basée sur la mastervalidation dans le référentiel local.
  2. Créez une nouvelle branche locale pour cette nouvelle origin/master-oldbranche (qui sera automatiquement configurée correctement en tant que branche de suivi).
  3. Pointez maintenant votre section locale mastervers le commit sur lequel vous souhaitez qu'il pointe.
  4. Enfin, forcez le changement masterdans le originréférentiel pour refléter votre nouveau local master.

(Si vous le faites d'une autre manière, vous avez besoin d'au moins une étape supplémentaire pour vous assurer qu'il master-oldest correctement configuré pour effectuer le suivi origin/master-old. Aucune des autres solutions publiées au moment de la rédaction de cet article ne comprend cela.)

Aristote Pagaltzis
la source
11
C'est une meilleure réponse que "la réponse", je suis d'accord, mais pour les gens qui sont venus ici pour renommer une branche (pas explicitement master), la 3ème étape n'a pas beaucoup de sens.
knocte
Cela ne fait absolument aucune différence dans la réponse, que vous soyez sur masterou dans une autre succursale. La question était cependant mal intitulée, elle concerne une tâche plus complexe que de simplement renommer une branche.
Aristote Pagaltzis
3
Cela s'est avéré être la solution qui a fonctionné pour moi. J'essayais de remplacer master par une autre branche. J'ai fait un git log -1 origin / what_i_want_as_new_master pour obtenir $ new_master_commit pour l'étape 3. Après le push (étape 4), d'autres développeurs tireraient et recevraient des messages "votre branche est en avance sur master par 295 commits." Pour résoudre ce problème, j'ai envoyé un e-mail les informant de chaque exécution: git pull; git checkout some_random_branch; git branch -D master; git pull; git checkout master; Fondamentalement, ils doivent supprimer leur maître local et extraire la nouvelle version sinon ils ne sont pas au bon endroit localement.
nairbv
Vous auriez pu le faire beaucoup plus facilement: en supposant qu'ils sont déjà masterallumés, ils pourraient simplement faire git fetch && git reset --hard origin/masterpour forcer leur section locale masterà être la même que celle activée origin. J'ai documenté cela, ainsi que le cas plus complexe où vous avez des commits locaux en plus de ceux masterque vous souhaitez conserver, dans stackoverflow.com/q/4084868
Aristotle Pagaltzis
Assurez-vous que le fichier de configuration distant contient "denyNonFastforwards = false" ou vous obtiendrez "remote: error: dening non-fast-forward refs / heads / master (you should pull first)"
gjcamann
160

Avec Git v1.7, je pense que cela a légèrement changé. La mise à jour de la référence de suivi de votre succursale locale vers la nouvelle télécommande est désormais très facile.

git branch -m old_branch new_branch         # Rename branch locally    
git push origin :old_branch                 # Delete the old branch    
git push --set-upstream origin new_branch   # Push the new branch, set local branch to track the new remote
Excalibur
la source
10
Une alternative à --set-upstreamest la suivante: Une fois que votre branche a été renommée localement et supprimée à l'origine, faites simplement: git push -u --all
lucifurious
4
Cela ne fonctionnera pas avec la branche master, car git ne vous permettra pas de supprimer le master distant.
Alexandre Neto
4
@AlexandreNeto Dans ce cas, vous pouvez exécuter la 3ème ligne avant la 2ème, définir la branche par défaut sur new_branchpuis supprimer éventuellement la télécommande masteravec la 2ème ligne.
Tristan Jahier du
3
Étapes incroyablement simples. C'est la meilleure réponse à la question
siddhusingh
13
Supprimer la branche distante git push origin --delete old_branchest légèrement plus lisible.
ThomasW
35
git checkout -b new-branch-name
git push remote-name new-branch-name :old-branch-name

Vous devrez peut-être basculer manuellement vers new-branch-nameavant de supprimerold-branch-name

Treken
la source
Une partie de cette solution supprime-t-elle l'ancien nom de la branche locale, ou s'agit-il d'un exercice distinct?
GreenAsJade
4
Je pense qu'à la fin doit être exécuté git branch -d old-branch-namepour supprimer l'ancienne branche locale.
Nabi KAZ
Vous pouvez pousser les changements par une seule commande: git push remote-name new-branch-name :old-branch-name.
sigod
De cette façon, ne compliquerez-vous pas l'histoire de Git? Parce que vous ouvrez une nouvelle branche au lieu de simplement renommer la branche actuelle.
androidevil
1
@androider No. Branches in git est une simple référence .
sigod
29

Il existe de nombreuses façons de renommer la branche, mais je vais me concentrer sur le plus gros problème: "comment permettre aux clients d'avancer rapidement et de ne pas avoir à jouer avec leurs branches localement" .

D'abord une image rapide: renommer la branche principale et permettre aux clients d'avancer rapidement

C'est quelque chose de facile à faire; mais n'en abusez pas. L'idée repose sur des commits de fusion; car ils permettent une avance rapide et lient les historiques d'une branche à une autre.

renommer la branche:

# rename the branch "master" to "master-old"
# this works even if you are on branch "master"
git branch -m master master-old

création de la nouvelle branche "master":

# create master from new starting point
git branch master <new-master-start-point>

créer un commit de fusion pour avoir un historique parent-enfant:

# now we've got to fix the new branch...
git checkout master

# ... by doing a merge commit that obsoletes
# "master-old" hence the "ours" strategy.
git merge -s ours master-old

et le tour est joué.

git push origin master

Cela fonctionne car la création d'une mergevalidation permet d' avancer rapidement la branche vers une nouvelle révision.

en utilisant un message de validation de fusion sensible:

renamed branch "master" to "master-old" and use commit ba2f9cc as new "master"
-- this is done by doing a merge commit with "ours" strategy which obsoletes
   the branch.

these are the steps I did:

git branch -m master master-old
git branch master ba2f9cc
git checkout master
git merge -s ours master-old
dnozay
la source
3
Merci! git merge -s ours master-oldest l'élément crucial que les autres réponses manquent. En outre, "facile à faire" ne signifie pas "facile à comprendre ou à découvrir", ce qui semble être le cas avec beaucoup de git, mais je m'égare.
Martin Vidner
3
J'adore le fait qu'aucune suppression ne soit mentionnée et que la transition pour ceux qui travaillent avec des clones en amont soit "sans couture". Je vous remercie!
Piotrek
12

Je suppose que vous posez toujours la même question que dans votre question précédente . Autrement dit, master-new ne contiendra pas master-old dans son historique. * Si vous appelez master-new "master", vous aurez effectivement réécrit l'historique. Peu importe comment vous entrez dans un état dans lequel le maître n'est pas un descendant d'une position précédente de maître, simplement qu'il est dans cet état.

Les autres utilisateurs qui tentent de tirer alors que le maître n'existe pas verront simplement leurs tirages échouer (aucune référence de ce type sur la télécommande), et une fois qu'il existera à nouveau dans un nouvel emplacement, leurs tirages devront tenter de fusionner leur maître avec le nouveau maître distant, comme si vous avez fusionné master-old et master-new dans votre référentiel. Étant donné ce que vous essayez de faire ici, la fusion entraînerait des conflits. (S'ils étaient résolus et que le résultat était repoussé dans le référentiel, vous seriez dans un état encore pire - les deux versions de l'historique là-bas.)

Pour répondre simplement à votre question: vous devez accepter que parfois il y aura des erreurs dans votre histoire. C'est d'accord. Ça arrive à tout le monde. Il y a des validations annulées dans le référentiel git.git. L'important est qu'une fois que nous publions l'histoire, c'est une chose à laquelle chacun peut faire confiance.

* Si c'était le cas, cela équivaudrait à pousser certains changements sur master, puis à créer une nouvelle branche là où elle était. Aucun problème.

Cascabel
la source
Oui, c'est le même problème, c'était juste une idée pour le résoudre. Mais même si je ne faisais pas ce changement de nom de branche, j'étais intéressant si c'était possible. Je pensais que des références telles que "master" ne sont que des références à des commits spécifiques. Je ne veux vraiment pas changer l'histoire. Je pensais simplement pointer la référence principale vers une autre tête. Cela signifie également que je ne pourrai plus jamais utiliser un nom de branche si je l'ai déjà utilisé auparavant.
Albert
En effet, les branches sont des références - des pointeurs vers les commits. Le fait est que nous nous attendons à ce que le chef d'une succursale évolue d'une manière particulière (à savoir, toujours une avance rapide). Du point de vue de quelqu'un d'autre, déplacer une branche dans votre référentiel public revient à réécrire l'historique de la branche. Il ne pointe plus vers un commit contenant tout ce qu'il avait l'habitude de faire.
Cascabel
8

La réponse sélectionnée a échoué lorsque je l'ai essayée. Il renvoie une erreur: refusing to delete the current branch: refs/heads/master. Je suppose que je posterai ce qui fonctionne pour moi:

git checkout master             # if not in master already

git branch placeholder          # create placeholder branch
git checkout placeholder        # checkout to placeholder
git push remote placeholder     # push placeholder to remote repository

git branch -d master            # remove master in local repository
git push remote :master         # remove master from remote repository.

L'astuce consiste à passer à l'espace réservé juste avant de le pousser vers le référentiel distant. Le reste est explicite, la suppression de la branche principale et la pousser vers le référentiel distant devrait fonctionner maintenant. Extrait d' ici .

Hendra Uzia
la source
Il échouerait sur git push remote: master si cela est vérifié du côté distant - vous verrez "remote: error:" comme préfixe dans les lignes du journal des erreurs.
rafalmag
2

Bien. Mes 2 cents. Que diriez-vous de vous connecter au serveur, d'aller dans le répertoire git et de renommer la branche dans le référentiel nu. Cela n'a pas tous les problèmes associés au re-upload de la même branche. En fait, les «clients» reconnaîtront automatiquement le nom modifié et changeront leur référence distante. Ensuite (ou avant), vous pouvez également modifier le nom local de la succursale.


la source
8
J'ai oublié les informations d'identification pour me connecter au serveur github. Toute personne possédant des informations d'identification :-P
Daniel Fisher lennybacon
1

Qu'en est-il de:

git checkout old-branch-name
git push remote-name new-branch-name
git push remote-name :old-branch-name
git branch -m new-branch-name
Hannes Tydén
la source
gâche le suivi des succursales - les utilisateurs peuvent avoir à réparer leur succursale localement?
dnozay
1

C'est la manière la plus simple et la plus lisible que je connaisse:

'Déplacer' la branche locale en utilisant -m

git branch -m my_old_branch_name my_new_branch_name

Poussez la branche «déplacée» vers la télécommande, définissez «en amont» à l'aide de -u

git push origin -u my_new_branch_name

(définir «en amont» «connecte» essentiellement votre branche locale à la télécommande, de sorte que des choses comme l'extraction, la traction et la poussée fonctionnent)

Supprimer l'ancienne branche de la télécommande

git push origin -D <old_name>

(votre succursale locale a déjà disparu, car vous l'avez "déplacée" lors de la 1ère étape)

Chris Halcrow
la source
1

OK , renommer une branche à la fois localement et sur la télécommande est assez facile! ...

Si vous êtes en succursale, vous pouvez facilement faire:

git branch -m <branch>

ou sinon, vous devez faire:

git branch -m <your_old_branch> <your_new_branch>

Ensuite, poussez la suppression vers la télécommande comme ceci:

git push origin <your_old_branch>

Maintenant que vous avez terminé, si vous obtenez une erreur en amont lorsque vous essayez de pousser, faites simplement:

git push --set-upstream origin <your_new_branch>

Je crée également l'image ci-dessous pour montrer les étapes en ligne de commande réelle, suivez simplement les étapes et vous seriez bon:

entrez la description de l'image ici

Alireza
la source
0

Vous pouvez effectuer les opérations suivantes:

git -m master master-old #rename current master
git checkout -b master   #create a new branch master
git push -f origin master #force push to master

Mais pousser de force est une mauvaise idée si d'autres personnes partagent ce référentiel. La poussée de force entraînera un conflit entre leur historique de révision et le nouveau.

Riyafa Abdul Hameed
la source
0

Les éléments suivants peuvent être enregistrés dans le script shell pour effectuer le travail:

Par exemple:

remote="origin"

if [ "$#" -eq 0 ] # if there are no arguments, just quit
then
    echo "Usage: $0 oldName newName or $0 newName" >&2
    exit 1
elif
    [ "$#" -eq 1 ] # if only one argument is given, rename current branch
then 
    oldBranchName="$(git branch | grep \* | cut -d ' ' -f2)" #save current branch name
    newBranchName=$1
else
    oldBranchName=$1
    newBranchName=$2
fi

git branch -m $oldBranchName $newBranchName

git push $remote :$oldBranchName #delete old branch on remote
git push --set-upstream $remote $newBranchName # add new branch name on remote and track it

Veuillez noter qu'ici le nom distant par défaut "origine" est codé en dur, vous pouvez étendre le script pour qu'il soit configurable!

Ensuite, ce script peut être utilisé avec des alias bash, des alias git ou, par exemple, dans des actions personnalisées sourcetree.

Do-do-new
la source
-1

Je crois que la clé est la réalisation que vous effectuez un double changement de nom: mastervers master-oldet aussi master-newvers master.

De toutes les autres réponses, j'ai synthétisé ceci:

doublerename master-new master master-old

où nous devons d'abord définir la doublerenamefonction Bash:

# doublerename NEW CURRENT OLD
#   - arguments are branch names
#   - see COMMIT_MESSAGE below
#   - the result is pushed to origin, with upstream tracking info updated
doublerename() {
  local NEW=$1
  local CUR=$2
  local OLD=$3
  local COMMIT_MESSAGE="Double rename: $NEW -> $CUR -> $OLD.

This commit replaces the contents of '$CUR' with the contents of '$NEW'.
The old contents of '$CUR' now lives in '$OLD'.
The name '$NEW' will be deleted.

This way the public history of '$CUR' is not rewritten and clients do not have
to perform a Rebase Recovery.
"

  git branch --move $CUR $OLD
  git branch --move $NEW $CUR

  git checkout $CUR
  git merge -s ours $OLD -m $COMMIT_MESSAGE

  git push --set-upstream --atomic origin $OLD $CUR :$NEW
}

Ceci est similaire à un changement d'historique git rebaseen ce que le contenu de la branche est assez différent, mais il diffère en ce que les clients peuvent toujours avancer rapidement en toute sécurité git pull master.

Martin Vidner
la source
-5
git update-ref newref oldref
git update-ref -d oldref newref
dlamotte
la source
2
Cela ne semble pas fonctionner pour moi, j'obtiens: git update-ref trunk trunk2 fatal: trunk2: pas un SHA1 valide
Gregg Lind