Renomeando ramificações remotamente no Git

407

Se houver um repositório ao qual eu tenha git://acesso apenas (e normalmente apenas pressione + puxe), existe uma maneira de renomear ramificações nesse repositório da mesma maneira que faria localmente git branch -m?

kdt
fonte
48
A pergunta "duplicada" vinculada pede para renomear um ramo "local e remoto". Essa pergunta, no entanto, pergunta apenas como renomear ramificações remotamente, o que permite uma simplificação. Isto é o que eu faço para mudar o nome de uma filial no servidor sem a necessidade de checkout e / ou criar uma filial local: git push origin origin/old_name:refs/heads/new_name && git push origin :old_name.
sschuberth
1
@sschuberth: você pode dar os dois comandos de uma só vez. E essa realmente deve ser a resposta para essa pergunta.
Joachim Breitner
2
@JoachimBreitner Você está certo, eu já fiz essa otimização neste script meu.
precisa saber é o seguinte
1
@sschuberth, você deve postar seu comentário como resposta, já que eu gosto mais do que os outros abaixo.
Phatmann
Feito .
sschuberth

Respostas:

480

Você só precisa criar uma nova ramificação local com o nome desejado, enviá-la para o controle remoto e excluir a ramificação remota antiga:

$ git branch new-branch-name origin/old-branch-name
$ git push origin --set-upstream new-branch-name
$ git push origin :old-branch-name

Então, para ver o antigo nome da filial, cada cliente do repositório teria que fazer:

$ git fetch origin
$ git remote prune origin

NOTA: Se o seu ramo antigo é o ramo principal, você deve alterar as configurações principais do ramo. Caso contrário, ao executar $ git push origin :old-branch-name, você receberá o erro "exclusão da ramificação atual proibida" .

Sylvain Defresne
fonte
8
Bem, se os nomes antigos e novos são os mesmos, significa que você não precisa renomear a ramificação; portanto, não há sentido em executar o comando em primeiro lugar ;-)
Sylvain Defresne
9
Certo. Quero apenas dizer que, se você está chamando isso de forma automatizada (como parte de algum outro script), é possível que não faça a coisa errada se puder evitá-la.
Mysterious Dan
9
O jeito de Dan: reordene os comandos para que eles sempre funcionem. Maneira do Earth Engine: lembre-se sempre de verificar ou você perde dados. Eu sei qual escolheria.
Doradus 27/10
2
Os usuários podem simplesmente executar: git fetch origin --prune(para buscar efetivamente as novas ramificações e também se livrar das referências que não estão mais no controle remoto).
DolphinDream 19/02
2
Pode usar -dou em --deletevez de :nas versões mais recentes do git.
Zitrax
285

Se você realmente deseja renomear ramificações remotamente, sem renomear nenhuma ramificação local ao mesmo tempo , faça isso com um único comando:

git push <remote> <remote>/<old_name>:refs/heads/<new_name> :<old_name>

Eu escrevi este script ( git-rename-remote-branch ) que fornece um atalho útil para fazer o que foi dito facilmente.

Como uma função bash:

git-rename-remote-branch(){
  if [ $# -ne 3 ]; then
    echo "Rationale : Rename a branch on the server without checking it out."
    echo "Usage     : $(basename $0) <remote> <old name> <new name>"
    echo "Example   : $(basename $0) origin master release"
    exit 1 
  fi

  git push $1 $1/$2:refs/heads/$3 :$2
}

Para integrar o comentário do @ ksrb : O que isso basicamente faz são dois toques em um único comando, primeiro git push <remote> <remote>/<old_name>:refs/heads/<new_name>para enviar uma nova ramificação remota com base na ramificação de rastreamento remoto antiga e depois git push <remote> :<old_name>excluir a ramificação remota antiga.

sschuberth
fonte
10
Para aqueles que desejam um apelido para esse comando: rename = "! F () {origem do git push origin / $ 1: refs / heads / $ 2: $ 1;}; f" isso pode ser usado como> git rename <old_name> < new_name>
Jonathan Schmidt
33
Para aqueles curiosos sobre o que esse comando realmente significa, basicamente, são 2 git push <remote>/<old_name>:refs/heads/<new_name> git push [space]:<old_name>
pushs
3
Por que você precisa usar refs/heads/name? Você não pode simplesmente usar namediretamente, fazendo o primeiro comando git push <remote> <remote>/<old_name>:<new_name>?
Drew Noakes
6
Não, porque a ramificação remota <new_name>ainda não existe. Se a ramificação não existir, o Git exigirá que você use o nome completo, caso contrário, <new_name>também poderá se referir a um nome de tag.
sschuberth
3
Usamos essa abordagem em nosso sistema de compilação. A única ressalva que encontramos é se refs/heads/<new_name> já existe. A exclusão ainda é bem-sucedida, resultando <remote>/<old_name>apenas na exclusão. Algumas verificações antes da mão podem facilmente evitar isso.
Apeiron
172

Primeiro faça o checkout no ramo que você deseja renomear:

git branch -m old_branch new_branch
git push -u origin new_branch

Para remover uma ramificação antiga de remote:

git push origin :old_branch
Shashank Hegde
fonte
12
Ao enviar o ramo renomeado (new_branch) para remoto (origem), você também deve configurá-lo para rastrear o ramo com o novo nome (por exemplo git push -u origin new_branch), caso contrário, o ramo renomeado (new_branch) continuará a rastrear o origin / old_branch. E depois que você excluir o old_branch remoto, o new_branch ainda rastreará a origem / old_branch, embora agora que a ramificação se foi.
DolphinDream 19/02
@ DolphinDream Editei a resposta para incluir sua alteração útil no upstream.
MVChr 15/09/16
10

Certo. Apenas renomeie a ramificação localmente, envie a nova ramificação e exclua a antiga.

O único problema real é que outros usuários do repositório não terão as ramificações de rastreamento local renomeadas.

Lily Ballard
fonte
1
então, ao tentar excluir o master, tentei o clone $ git ../src $ cd src $ filial git notmaster $ git checkout notmaster $ filial git -d mestre $ git push ../src: master Mas reclama: O destino refspec não corresponde a uma referência existente no controle remoto nem começa com refs /, e não podemos adivinhar um prefixo com base na fonte ref. erro: falha ao enviar algumas referências para '../alpha/' O controle remoto realmente tem uma ramificação chamada master
kdt
2

TL; DR

"Renomear" uma ramificação remota é na verdade um processo de duas etapas (não necessariamente solicitado):

  • exclusão da ramificação remota antiga ( git push [space]:<old_name>como o ksrb explicou );
  • envie para uma nova ramificação remota (diferença entre alguns comandos de respostas abaixo).

Excluindo

Eu uso o TortoiseGit e quando tentei excluir o ramo pela linha de comando, obtive o seguinte:

$ git push origin :in
  • fatal: 'origin' não parece ser um repositório git

  • fatal: Não foi possível ler do repositório remoto.

Verifique se você possui os direitos de acesso corretos e se o repositório existe.

Isso provavelmente ocorreu devido ao concurso não ter a chave privada carregada (que o TortoiseGit carrega automaticamente no concurso ). Além disso, notei que os comandos do TortoiseGit não possuem a originreferência neles (por exemplo git.exe push --progress "my_project" interesting_local:interesting).

Também estou usando o Bitbucket e, como outros gerenciadores de git on-line baseados na Web (GitHub, GitLab), pude excluir a ramificação remota diretamente através de sua interface (página de ramificações):

Excluir ramificação Bitbucket

No entanto, no TortoiseGit, você também pode excluir ramificações remotas através de Browse References :

Menu Procurar referências

Ao clicar com o botão direito do mouse em uma ramificação remota (lista de controles remotos), a opção Excluir ramificação remota é exibida:

Exclusão de ramificação remota do TortoiseGit

Empurrando

Após excluir a ramificação remota antiga, enviei diretamente para uma nova ramificação remota através do TortoiseGit, apenas digitando o novo nome no campo Remote: da janela Push e essa ramificação foi criada e visível automaticamente no Bitbucket .

No entanto, se você ainda preferir fazê-lo manualmente, um ponto que ainda não foi mencionado neste segmento é que -u= --set-upstream.

Nos git pushdocumentos , -ué apenas um alias de --set-upstream, portanto, os comandos nas respostas de Sylvain ( -set-upstream new-branch) e Shashank ( -u origin new_branch) são equivalentes, já que a referência remota é padronizada comoorigin se nenhuma outra referência foi definida anteriormente:

  • git push origin -u new_branch= git push -u new_branch da descrição do documento :

    Se a configuração estiver ausente, o padrão será origin.

No final, eu não digitei manualmente ou usei nenhum dos comandos sugeridos pelas outras respostas aqui, então talvez isso possa ser útil para outras pessoas em uma situação semelhante.

CPHPython
fonte
o problema é que seu controle remoto não é chamado origin. Você precisa nomear o seu controle remoto ao executá-lo git remote. O Git funciona com o sshque implica que você está usando chaves públicas + privadas. Eu assumo que oAutoload Putty keys TortoiseGit esteja apenas carregando automaticamente as chaves necessárias para que você faça qualquer coisa com sua referência remota. A última coisa é que git push -unão é um alias para enviar para uma ramificação remota, é um alias para enviar para uma ramificação remota que foi criada localmente e sua referência remota ainda não tem essa ramificação .
juanecabellob
1
@juancab -ué um pseudônimo de --set-upstream"se a configuração estiver ausente, o padrão seráorigin ". Sylvain e Shashank usam isso para enviar para um ramo remoto recém-criado . O principal problema pode ter sido devido ao concurso não ter carregado quando tentei git push origin :inno shell. Portanto, não entendo seu voto negativo, apenas apontei os meus e os detalhes não endereçados em outras respostas, expliquei-os e resolvi-os.
CPHPython
Você está afirmando coisas erradas e grande parte dessa resposta não tem relação com a pergunta em si. Se você está apontando o que funcionou para você, encorajo-o a limitar a resposta ao que funcionou e se você realmente deseja dar uma explicação, informe-se melhor. Btw: -ué um apelido para, --set-upstreammas não um apelido para enviar para um ramo remoto, como você disse. Para entrar em uma ramificação remota, você precisa exclusivamente git push <remote>e, se ainda não estiver na remota, adicione git push -u <remote>. Portanto, -ué usado para criar uma referência da ramificação no controle remoto.
juanecabellob
1
@juancab talvez o que você considera errado foi principalmente o apelido fraseado ou escolha de palavras. Reestruturei minha resposta e reformulei-a para fornecer uma explicação completa das soluções que encontrei para renomear uma filial remota.
CPHPython
Eu reformularia ainda mais. Faz mais sentido agora, mas ainda é muito longo. Eu seria mais específico ao problema, ou seja, afirmo que para os usuários do TortoiseGit as soluções propostas não funcionarão. Você está contando uma história, isso é confuso e faz com que os usuários evitem ler. Vou editar sua resposta com uma proposta.
juanecabellob
1

Não sei por que, mas a resposta de @Sylvain Defresne não funciona para mim.

git branch new-branch-name origin/old-branch-name
git push origin --set-upstream new-branch-name
git push origin :old-branch-name

Eu tenho que desconfigurar o upstream e então posso definir o stream novamente. A seguir, é como eu fiz isso.

git checkout -b new-branch-name
git branch --unset-upstream
git push origin new-branch-name -u
git branch origin :old-branch-name
Arthur Bryant
fonte
0

Não sei se isso está certo ou errado, mas coloquei o "nome antigo" do ramo no "novo nome" do ramo e excluí o ramo antigo inteiramente com as duas linhas a seguir:

git push origin old_branch:new_branch
git push origin :old_branch
EpicPandaForce
fonte
Tanto quanto posso dizer, é exatamente isso que todas as outras respostas fazem. Sua resposta é apenas mais sucinta.
Clearer
-1

Você pode criar uma nova ramificação com base na ramificação de nome antigo. Assim, exclua a ramificação antiga !!!insira a descrição da imagem aqui

Pober Wong
fonte
Esse é o GitHub, não o Git. ;)
Bouncner
-4

Além das respostas já fornecidas, aqui está uma versão que primeiro verifica se o novo ramo já existe (para que você possa usá-lo com segurança em um script)

if git ls-remote --heads "$remote" \
    | cut -f2 \
    | sed 's:refs/heads/::' \
    | grep -q ^"$newname"$; then
    echo "Error: $newname already exists"
    exit 1
fi
git push "$oldname" "$remote/$oldname:refs/heads/$newname" ":$oldname"

(a verificação é desta resposta )

myzzzl
fonte
Eu teria usado em git show-ref --quiet --verify -- refs/heads/$new_namevez de ls-remote | cut | sed | grep.
21417 Andy