在Git中远程重命名分支

443
如果我只有git://访问权限(通常只是推送+拉取)的存储库,是否有一种方法可以像在本地使用git branch -m一样重命名该存储库中的分支?

51
相关的“重复”问题要求在本地和远程同时重命名分支。然而,这个问题只是询问如何在远程重命名分支,这样可以简化操作。以下是我在服务器上重命名分支的步骤,无需检出或创建本地分支:git push origin origin/old_name:refs/heads/new_name && git push origin :old_name - sschuberth
1
@sschuberth:你可以一次性输入两个命令。这真的应该是这个问题的答案。 - Joachim Breitner
2
@JoachimBreitner 你说得对,我已经在我的这个脚本中进行了这个优化。 - sschuberth
1
@sschuberth,你应该把你的评论发布为答案,因为我比下面的其他评论更喜欢它。 - phatmann
已完成:https://dev59.com/D2445IYBdhLWcg3wpcAP#21302474。 - sschuberth
显示剩余4条评论
10个回答

509

您只需创建一个具有所需名称的新本地分支,将其推送到远程,然后删除旧的远程分支:

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

那么,要查看旧分支的名称,每个代码库的客户端都需要执行以下操作:

$ git fetch origin
$ git remote prune origin

注意:如果您的旧分支是您的主分支,那么您应该更改您的主分支设置。否则,当您运行$ git push origin :old-branch-name时,您会收到错误消息"deletion of the current branch prohibited"


8
如果旧名称和新名称相同,那么意味着您不需要重命名分支,因此首先运行该命令没有任何意义;-) - Sylvain Defresne
9
当然。我的意思是,如果您是以自动化方式调用它(作为其他脚本的一部分),如果可以避免执行错误操作,那么最好不要让它这样做。 - Mysterious Dan
9
丹的方法:重新排列命令,以便它们始终正常工作。地球引擎的方法:始终记得检查,否则你会丢失数据。我知道我会选择哪一个。 - Doradus
2
用户只需运行:git fetch origin --prune(以有效地获取新分支并摆脱不再在远程的引用)。 - DolphinDream
4
在新版本的 Git 中,可以使用 -d--delete 替代 : - Zitrax
显示剩余6条评论

321

如果你只是想远程重命名分支,而不是同时重命名任何本地分支,你可以使用一个单独的命令来完成:

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

我编写了这个脚本 (git-rename-remote-branch),它为以上操作提供了一个方便的快捷方式。

作为Bash函数:

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

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

为了融入@ksrb的评论:这基本上是在一个单独的命令中进行两次推送,首先使用git push <remote> <remote>/<old_name>:refs/heads/<new_name>推送一个基于旧的远程跟踪分支的新远程分支,然后使用 git push <remote> :<old_name>删除旧的远程分支。


11
对于那些想要该命令的别名的人:rename = "!f() { git push origin origin/$1:refs/heads/$2 :$1; } ; f",这可以用作> git rename <old_name> <new_name>。 - Jonathan Schmidt
35
对于那些好奇这个命令到底是什么意思的人,它基本上包含了两个步骤。 git push <remote>/<old_name>:refs/heads/<new_name> 表示推送一个新的远程分支,使用旧的远程分支作为源。 然后 git push [space]:<old_name> 表示删除旧的远程分支。 - ksrb
3
为什么需要使用refs/heads/name?你不能直接使用name吗?这样第一个命令就变成了git push <remote> <remote>/<old_name>:<new_name> - Drew Noakes
7
不行,因为远程分支 <new_name> 还不存在。如果该分支不存在,Git 要求您使用完整名称,否则 <new_name> 可能也会引用标签名称。 - sschuberth
4
我们在构建系统中使用这种方法。唯一需要注意的是,如果 refs/heads/<new_name> 已经存在,则删除操作仍会成功,导致只有 <remote>/<old_name> 被删除。预先进行一些检查就可以轻松避免这种情况。 - Apeiron
显示剩余11条评论

189

首先检出你想要重命名的分支:

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

要从远程中删除旧分支:

git push origin :old_branch

15
当你将重命名的分支(new_branch)推送到远程(origin)时,你还应该设置它的上游分支来跟踪新名称的分支 (例如 git push -u origin new_branch),否则重命名后的分支(new_branch)仍会继续跟踪 origin/old_branch。一旦你删除了远程的 old_branch,new_branch仍然会跟踪origin/old_branch,尽管这个分支已经不存在了。 - DolphinDream
1
@DolphinDream,我编辑了答案,包括了你有用的上游更改。 - mVChr

11

可以。只需在本地重命名分支,推送新分支,然后删除旧分支。

唯一的问题是仓库的其他用户不会将本地跟踪分支重命名。


1
所以在尝试删除主分支时,我尝试了以下操作: $ git clone ../src $ cd src $ git branch notmaster $ git checkout notmaster $ git branch -d master $ git push ../src :master但是它报错了:目标 refspec 既不匹配远程上的现有 ref,也不以 refs/ 开头,我们无法根据源 ref 猜测前缀。 错误:无法将某些 ref 推送到 '../alpha/'实际上,远程确实有一个名为 master 的分支。 - kdt

5

更改分支名称,请按以下步骤操作:

  1. git branch -m old_branchname new_branchname
  2. git push origin :old_branchname new_branchname
  3. git push --set-upstream origin new_branchname

完成后获取 origin

  1. git fetch origin
  2. git remote prune origin

2

简述

"重命名"远程分支实际上是一个两步骤过程(不一定按顺序):

  • 删除旧的远程分支(使用命令git push [space]:<old_name>,如ksrb explained所述);
  • 推送到新的远程分支(下面这些答案的命令有所区别)。

删除

我使用TortoiseGit,当我第一次尝试通过命令行删除分支时,出现了以下情况:

$ git push origin :in
  • fatal: 'origin' does not appear to be a git repository

  • fatal: Could not read from remote repository.

Please make sure you have the correct access rights and the repository exists.

这可能是由于 pageant 没有加载 私钥(而 TortoiseGit 会自动加载到 pageant 中)所导致的。此外,我注意到 TortoiseGit 命令中没有 origin 引用(例如:git.exe push --progress "my_project" interesting_local:interesting)。
我还使用 Bitbucket,像其他基于 Web 的 Git 管理器一样(如 GitHub、GitLab),我能够直接通过它们的界面(分支页面)删除远程分支。

Delete branch Bitbucket

然而,在TortoiseGit中,你也可以通过“浏览引用”删除远程分支:

Browse References menu

通过右键单击远程分支(远程列表),将出现“删除远程分支”选项:

TortoiseGit remote branch delete

推送

在删除旧的远程分支后,通过 TortoiseGit 直接将新名称输入到 Push 窗口的 Remote: 字段中,我成功地将代码推送到了一个新的远程分支,并且这个分支会自动在 Bitbucket 上创建并显示。

然而,如果您仍然喜欢手动操作,本文中还未提及的一点是,-u = --set-upstream

根据 git push 文档-u 只是 --set-upstream 的别名,因此 Sylvain (-set-upstream new-branch)Shashank (-u origin new_branch) 中的命令是等效的,因为如果没有定义其他引用,则远程引用默认为 origin

  • git push origin -u new_branch = git push -u new_branch,意思是从文档描述中可以看到:如果缺少配置,默认为origin

最终,我没有手动输入或使用其他答案中建议的任何命令,因此这可能对其他遇到类似情况的人有用。


问题在于你的远程库没有被称为 origin。你必须按照运行命令 git remote 获取到的名称来命名你的远程库。Git 使用 ssh,这意味着你正在使用公钥和私钥。我假设 TortoiseGit 的 Autoload Putty keys 只是自动加载所需的密钥,以便你可以对远程引用进行任何操作。最后一件事是,git push -u 不是将内容推送到远程分支的别名,而是将内容推送到本地创建但其远程引用尚未拥有该分支的远程分支的别名。 - juanecabellob
1
@juancab -u--set-upstream 的别名,"如果配置缺失,则默认为 origin"(参见git-push文档)。SylvainShashank 使用它来 推送到一个新创建的远程分支。关键问题可能是由于在 shell 上尝试 git push origin :inpageant 没有加载它。所以我不明白你的反对意见,我只是指出了我的答案和其他答案中未解决的细节,并加以解释和解决。 - CPHPython
你说了一些错误的事情,而且这个回答中很多内容与问题本身无关。如果你想指出什么对你有用,请限制回答只包括它确实有效的部分,如果你真的想解释,请更好地了解一下。顺便说一句:-u--set-upstream的别名,但它不是像你说的那样推送到远程分支的别名。要将更改推送到远程分支,你需要使用git push <remote>,如果它还没有在远程分支中,则添加git push -u <remote>。因此,-u用于在远程创建分支的引用。 - juanecabellob
1
@juancab也许你认为错误的主要是“别名(alias)”措辞或用词选择。我重新组织了我的答案,并重新措辞,以便提供我发现的重命名远程分支的完整解决方案的解释。 - CPHPython
我会进一步重新表述它。现在更有意义了,但还是太长了。我会更具体地说明问题,即指出对于TortoiseGit用户,建议的解决方案行不通。你正在讲故事,这很令人困惑,使用户避免阅读。 我将用一个建议来编辑你的答案。 - juanecabellob

1

我不知道为什么,但 @Sylvain Defresne 的答案对我无效。

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

我必须取消设置上游,然后才能再次设置流。以下是我的操作步骤。

git checkout -b new-branch-name
git branch --unset-upstream
git push origin new-branch-name -u
git branch origin :old-branch-name

1

我不知道这样做是对还是错,但我将分支的“旧名称”推送到分支的“新名称”,然后用以下两行代码完全删除了旧分支:

git push origin old_branch:new_branch
git push origin :old_branch

据我所知,这正是所有其他答案所做的。您的答案只是更简洁。 - Clearer

0
如果您正在使用Github...
您可以在github.com上使用UI基于旧名称分支创建新分支:

Branch Rename


那是GitHub,不是Git。;) - Bouncner

-4

除了已经给出的答案,这里有一个版本,首先检查新分支是否已经存在(因此您可以在脚本中安全使用它)

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"

(检查来自此答案


我会使用 git show-ref --quiet --verify -- refs/heads/$new_name 而不是 ls-remote | cut | sed | grep - Andy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接