Renomear ramificação principal para repositórios Git locais e remotos


821

Eu tenho o ramo masterque rastreia o ramo remoto origin/master.

Eu quero renomeá-los para master-oldlocalmente e no controle remoto. Isso é possível?

Para outros usuários que rastrearam origin/master(e que sempre atualizavam sua masterfilial local via git pull), o que aconteceria depois que eu renomeasse a filial remota?
Eles git pullainda funcionariam ou gerariam um erro que não conseguiam origin/mastermais encontrar ?

Depois, quero criar uma nova masterramificação (local e remota). Novamente, depois que eu fiz isso, o que aconteceria agora se os outros usuários fizessem git pull?

Eu acho que tudo isso resultaria em muitos problemas. Existe uma maneira limpa de conseguir o que quero? Ou devo apenas deixar mastercomo está e criar um novo ramo master-newe apenas trabalhar mais lá?


2
A receita dada na resposta aceita se aplica a uma ramificação de qualquer nome, mas as advertências (conforme observado) não, devido à função especial (por padrão) da ramificação principal no Git.
Kryan

3
@kynan: Eu acho que não entendo. Quais advertências se aplicam ao mestre e não se aplicam a outros ramos? Se fosse um ramo chamado xy e outras pessoas o rastrearam, como isso seria diferente?
19412 Albert

4
A ressalva de que você normalmente não pode excluir o mestre remoto. Isso não se aplica à resposta de Aristóteles, portanto, você pode marcar isso como a resposta aceita. Você está correto, qualquer um git push -fafeta a capacidade de pullpartir de qualquer ramo de rastreamento remoto.
Kynan

você pode criar um novo ramo master-oldque aponte para o mesmo commit que o masterramo anterior . Em seguida, você pode sobrescrever a masterramificação com suas novas alterações, fazendo um mergecom a oursestratégia. Fazer uma mesclagem funciona quando o controle remoto não permite alterações não avançadas. Isso também significa que outros usuários não terão atualizações forçadas.
dnozay

1
O @kynan masteré especial apenas desde que seja o único ramo existente. Assim que você tiver mais de um, todos os ramos estarão em pé de igualdade.
Jub0bs # 14/14

Respostas:


615

O mais próximo a renomear é excluir e depois recriar no controle remoto. Por exemplo:

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

No entanto, isso tem muitas advertências. Primeiro, nenhum checkout existente saberá sobre a renomeação - o git não tenta rastrear as renomeações de ramificações. Se o novo masterainda não existir, o git pull apresentará um erro. Se o novo masterfoi criado. a atração tentará mesclar mastere master-old. Portanto, geralmente é uma má idéia, a menos que você tenha a cooperação de todos que fizeram check-out no repositório anteriormente.

Nota: As versões mais recentes do git não permitem excluir a ramificação principal remotamente por padrão. Você pode substituir isso definindo o receive.denyDeleteCurrentvalor de configuração para warnou ignoreno repositório remoto . Caso contrário, se você estiver pronto para criar um novo mestre imediatamente, pule a git push remote :masteretapa e passe --forcepara a git push remote masteretapa. Observe que, se você não conseguir alterar a configuração do controle remoto, não poderá excluir completamente o ramo mestre!

Esta ressalva se aplica apenas ao ramo atual (geralmente o masterramo); qualquer outro ramo pode ser excluído e recriado como acima.


2
ramos são apenas um par (nome, hash) - nada mais, nada menos. Existe o reflog nas ramificações, mas isso nunca é exposto a clientes remotos.
bdonlan

122
Eu criaria o master-old no controle remoto antes de excluir o master no controle remoto. Eu sou apenas paranóico.
Adam Dymitruk

6
A resposta de Aristóteles abaixo permite que você faça isso sem excluir o mestre, então acho isso preferível.
argila Bridges

13
seria claro e seguro se você pode usar new-branch-namee, em old-branch-namevez de master/ master-old, portanto, esse é um problema geral.
Jaider

2
Se a ramificação excluída (aqui: master) não for referenciada por outras ramificações, o git poderá coletar todos os commits nessa lixo ... bem ... "ramificação". - Alguns comandos de porcelana git acionam uma coleta de lixo. - Portanto: crie o novo nome primeiro (apontando para o mesmo commit) e, em seguida, exclua o nome antigo.
Robert Siemer 14/01

257

Supondo que você esteja atualmente 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. Primeiro, faça uma master-oldramificação no originrepositório, com base na masterconfirmação no repositório local.
  2. Crie uma nova ramificação local para essa nova origin/master-oldramificação (que será automaticamente configurada corretamente como uma ramificação de rastreamento).
  3. Agora aponte seu local masterpara o que você deseja confirmar.
  4. Por fim, force a alteração masterno originrepositório para refletir seu novo local master.

(Se você fizer isso de qualquer outra maneira, precisará de pelo menos mais uma etapa para garantir que master-oldesteja configurado corretamente para acompanhar origin/master-old. Nenhuma das outras soluções postadas no momento da redação deste artigo inclui isso.)


11
Esta é uma resposta melhor do que "a resposta", eu concordo, mas para as pessoas que vieram aqui apenas para renomear um ramo (não explicitamente mestre), o terceiro passo não faz muito sentido.
knocte

Não faz absolutamente nenhuma diferença para a resposta se você está em masterou outro ramo. A questão foi mal intitulada, porém, pergunta sobre uma tarefa mais complexa do que apenas renomear um ramo.
Aristóteles Pagaltzis

3
Essa acabou sendo a solução que funcionou para mim. Eu estava tentando substituir o mestre por outro ramo. Eu fiz uma origem git log -1 / what_i_want_as_new_master para obter o $ new_master_commit para a etapa 3. Após o push (etapa 4), outros desenvolvedores receberiam mensagens "seu ramo está à frente do mestre por 295 confirmações". Para corrigir isso, enviei um e-mail informando a cada execução: git pull; git checkout some_random_branch; git branch -D master; git pull; mestre de checkout do git; Basicamente, eles precisam remover o mestre local e extrair a nova versão, caso contrário, eles estão no local errado localmente.
nairbv

Você poderia ter feito isso com muito mais facilidade: supondo que eles já estejam ligados master, eles poderiam apenas fazer git fetch && git reset --hard origin/masterpara forçar o local mastera ser o mesmo que o local origin. Eu documentei isso, bem como o caso mais complexo em que você tem confirmações locais além das masterque deseja manter, em stackoverflow.com/q/4084868
Aristotle Pagaltzis

Certifique-se de que o arquivo de configuração remoto tem "denyNonFastforwards = false" ou você vai ficar "remoto: erro: negar não-fast-forward refs / heads / master (você deve puxar primeiro)"
gjcamann

160

Com o Git v1.7, acho que isso mudou um pouco. Atualizar a referência de rastreamento da sua filial local para o novo controle remoto agora é muito fácil.

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

10
Uma alternativa para --set-upstreamé a seguinte: Depois de ter seu ramo renomeado localmente e apagados na origem, basta fazer: git push -u --all
lucifurious

4
Isso não funcionará com ramificação mestre, pois o git não permitirá que você exclua o mestre remoto.
Alexandre Neto

4
@AlexandreNeto Nesse caso, você pode executar a 3ª linha antes da 2ª, definir a ramificação padrão como new_branche, eventualmente, excluir o controle remoto mastercom a 2ª linha.
Tristan Jahier 03/02

3
Passos incrivelmente simples. Esta é a melhor resposta da pergunta
siddhusingh

13
Excluir a ramificação remota git push origin --delete old_branché um pouco mais legível.
Thomasw

35
git checkout -b new-branch-name
git push remote-name new-branch-name :old-branch-name

Pode ser necessário alternar manualmente para new-branch-nameantes de excluirold-branch-name


Alguma parte desta solução exclui o nome antigo do ramo local ou é um exercício separado?
GreenAsJade 15/09/13

4
Eu acho que no final deve ser executado git branch -d old-branch-namepara excluir o ramo antigo local.
Nabi KAZ

Você pode empurrar mudanças por apenas um comando: git push remote-name new-branch-name :old-branch-name.
sigod

Dessa forma, você não complicará a história do git? Como você está abrindo um novo ramo, apenas renomeie o atual.
androidevil 23/01

1
@androider Não. Ramos no git são referências simples .
21414 sigl

29

Existem várias maneiras de renomear a filial, mas vou focar no problema maior: "como permitir que os clientes avancem rapidamente e não precisem mexer com suas ramificações localmente" .

Primeiro, uma imagem rápida: renomear filial principal e permitir que os clientes avancem rapidamente

Isso é algo realmente fácil de fazer; mas não abuse. A idéia toda depende de consolidação de mesclagem; pois eles permitem o avanço rápido e vinculam os históricos de um ramo a outro.

renomeando a ramificação:

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

criando o novo ramo "mestre":

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

criando uma consolidação de mesclagem para ter um histórico pai-filho:

# 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

e voila.

git push origin master

Isso funciona porque a criação de uma mergeconfirmação permite o avanço rápido da ramificação para uma nova revisão.

usando uma mensagem de confirmação de mesclagem sensata:

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

3
Obrigado! git merge -s ours master-oldé a peça crucial que as outras respostas perdem. Além disso, "fácil de fazer" não significa "fácil de entender ou descobrir", que parece ser o caso de grande parte do git, mas discordo.
Martin Vidner

3
Eu amo o fato de que nenhuma exclusão é mencionada e que a transição para aqueles que trabalham com clones do upstream é "contínua". Obrigado!
Piotrek

12

Suponho que você ainda esteja perguntando sobre a mesma situação da sua pergunta anterior . Ou seja, master-new não conterá master-old em sua história. * Se você chamar master-new "master", efetivamente terá reescrito o histórico. Não importa como você entra em um estado em que o mestre não é descendente de uma posição anterior do mestre, simplesmente que ele está nesse estado.

Outros usuários que tentarem puxar enquanto o mestre não existir, simplesmente terão seus puxões falhados (não há ref no controle remoto) e, uma vez que ele exista novamente em um novo local, os puxadores precisarão tentar mesclar seu mestre com o novo mestre remoto, como se você mesclasse master-old e master-new em seu repositório. Dado o que você está tentando fazer aqui, a mesclagem teria conflitos. (Se eles foram resolvidos e o resultado foi empurrado de volta para o repositório, você estaria em um estado ainda pior - as duas versões do histórico lá.)

Para responder sua pergunta com simplicidade: você deve aceitar que, às vezes, haverá erros em sua história. Esta certo. Isso acontece com todo mundo. Existem confirmações revertidas no repositório git.git. O importante é que, depois que publicamos a história, é algo em que todos podem confiar.

* Se isso acontecesse, isso seria equivalente a fazer algumas alterações no mestre e criar uma nova ramificação onde costumava estar. Sem problemas.


Sim, é o mesmo problema, apenas uma ideia de como resolvê-lo. Mas mesmo que eu não fizesse essa renomeação de ramificações, eu era interessante se isso fosse possível. Eu pensei que árbitros como "mestre" são apenas referências a commits específicos. Eu realmente não quero mudar nenhuma história. Pensei em apontar a referência principal para outra cabeça. Isso também significa que nunca mais poderei usar um nome de filial se já o tiver usado antes?
Albert

De fato, as ramificações são referências - indicadores de confirmações. O fato é que esperamos que o chefe de um ramo evolua de uma maneira específica (ou seja, sempre avançando rapidamente). Do ponto de vista de outra pessoa, mover uma ramificação em seu repositório público é o mesmo que reescrever o histórico da ramificação. Já não aponta para um commit contendo tudo o que costumava.
Cascabel

8

A resposta selecionada falhou quando tentei. Ele lança um erro: refusing to delete the current branch: refs/heads/master. Acho que vou postar o que funciona para mim:

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.

O truque é fazer checkout no espaço reservado logo antes de enviá-lo para o repositório remoto. O restante é auto-explicativo, excluir a ramificação principal e enviá-la ao repositório remoto deve funcionar agora. Extraído daqui .


Isso falharia no git push remote: master se isso estiver marcado no lado remoto - você verá "remote: error:" como prefixo nas linhas do log de erros.
Rafalmag 13/04

2

Boa. Meus 2 centavos. Que tal fazer logon no servidor, acessar o diretório git e renomear a filial no repositório vazio. Isso não tem todos os problemas associados ao re-upload da mesma ramificação. Na verdade, os 'clientes' reconhecerão automaticamente o nome modificado e mudarão sua referência remota. Depois (ou antes), você também pode modificar o nome local da filial.


8
Esqueci as credenciais para fazer logon no servidor github. Qualquer pessoa com credenciais por aí :-P
Daniel Fisher lennybacon

1

A respeito:

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

mexe com o rastreamento de filiais - os usuários podem precisar corrigir sua filial localmente?
dnozay

1

Esta é a maneira mais simples e mais 'legível' que eu conheço:

'Mover' ramificação local usando -m

git branch -m my_old_branch_name my_new_branch_name

Empurre o ramo 'movido' para o controle remoto, defina 'upstream' usando -u

git push origin -u my_new_branch_name

(configurar 'upstream' essencialmente 'conecta' sua filial local ao controle remoto, para que coisas como buscar, puxar e empurrar funcionem)

Exclua a ramificação antiga do controle remoto

git push origin -D <old_name>

(sua filial local já se foi, porque você a moveu na 1ª etapa)


1

OK , renomear uma filial localmente e no controle remoto é bastante fácil! ...

Se você estiver no ramo, poderá fazer facilmente:

git branch -m <branch>

ou, se não, você precisa fazer:

git branch -m <your_old_branch> <your_new_branch>

Em seguida, empurre a exclusão para o controle remoto assim:

git push origin <your_old_branch>

Agora você terminou, se você receber um erro de upstream enquanto tenta enviar, basta:

git push --set-upstream origin <your_new_branch>

Também crio a imagem abaixo para mostrar as etapas na linha de comando real, basta seguir as etapas e você seria bom:

insira a descrição da imagem aqui


0

Você pode fazer o seguinte:

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

Mas forçar é uma má idéia se outras pessoas estiverem compartilhando este repositório. O envio forçado fará com que o histórico de revisões entre em conflito com o novo.


0

O seguinte pode ser salvo no script de shell para executar o trabalho:

Por exemplo:

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

Observe que aqui o nome remoto padrão "origem" é codificado, você pode estender o script para torná-lo configurável!

Em seguida, esse script pode ser usado com aliases de bash, aliases de git ou, por exemplo, em ações customizadas de código fonte.


-1

Acredito que a chave é a percepção de que você está realizando um duplo renomear: masterpara master-olde também master-newpara master.

De todas as outras respostas, eu sintetizei isso:

doublerename master-new master master-old

onde primeiro precisamos definir a doublerenamefunção 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
}

Isso é semelhante a uma mudança git rebaseno histórico em que o conteúdo da filial é bem diferente, mas difere no fato de os clientes ainda poderem avançar com segurança git pull master.


-5
git update-ref newref oldref
git update-ref -d oldref newref

2
Isso não parece trabalhar para mim, eu recebo: update-ref git tronco trunk2 fatal: trunk2: não um SHA1 válida
Gregg Lind
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.