为本地和远程Git存储库重命名主分支

我有分支master跟踪远程分支origin/master

我想在本地和远程将它们重命名为master-old。这可能吗?

对于跟踪origin/master的其他用户(并且总是通过git pull更新其本地master分支),我重命名远程分支后会发生什么?
他们的git pull还能工作吗?还是会抛出一个找不到origin/master的错误?

然后,进一步,我想创建一个新的master分支(本地和远程)。同样,在我这样做之后,如果其他用户做git pull,现在会发生什么?

我想所有这些都会带来很多麻烦。有没有一种干净的方法来得到我想要的?或者我应该保留master,创建一个新的分支master-new,然后在那里继续工作?

315826 次浏览

我假设你仍然在问与你的上一个问题相同的情况。也就是说,master-new在其历史中不包含master-old。*如果你称master-new为“master”,你实际上已经重写了历史。如何你进入一个master不是先前master位置的后代的状态并不重要,只是它处于那个状态。

其他用户在master不存在时尝试拉取只会导致拉取失败(远程上没有这样的ref),一旦它在新的地方再次存在,他们的拉取将不得不尝试将他们的master与新的远程master合并,就像你在存储库中合并了master-old和master-new一样。考虑到你在这里试图做的事情,合并会有冲突。(如果它们被解决了,结果被推回到存储库中,你会处于更糟糕的状态——那里有两个历史版本。)

简单地回答你的问题:你应该接受历史记录中有时会出现错误。这没关系。每个人都会发生这种情况。git.git存储库中有还原的提交。重要的是,一旦我们发布历史记录,这是每个人都可以信任的。

*如果是这样,这相当于将一些更改推送到master上,然后在原来的位置创建一个新分支。没问题。

最接近重命名的是删除,然后在远程上重新创建。例如:

git branch -m master master-oldgit push remote :master         # Delete mastergit push remote master-old      # Create master-old on remote
git checkout -b master some-ref # Create a new local mastergit push remote master          # Create master on remote

然而,这有很多警告。首先,没有现有的签出将知道重命名-Git没有尝试跟踪分支重命名。如果新的master还不存在,git拉取将出错。如果新的master已经创建。拉取将尝试合并mastermaster-old。所以这通常是一个坏主意,除非你有之前签出存储库的每个人的合作。

注意:默认情况下,较新版本的Git不允许您远程删除master分支。您可以通过在远程存储库中将receive.denyDeleteCurrent配置值设置为warnignore来覆盖这一点。否则,如果您准备好立即创建新master,请跳过git push remote :master步骤,并将--force传递到git push remote master步骤。请注意,如果您无法更改远程配置,您将无法完全删除master分支!

此警告仅适用于当前分支(通常是master分支);任何其他分支都可以像上面一样删除和重新创建。

git update-ref newref oldrefgit update-ref -d oldref newref

关于什么:

git checkout old-branch-namegit push remote-name new-branch-namegit push remote-name :old-branch-namegit branch -m new-branch-name

假设您当前位于master

git push origin master:master-old        # 1git branch master-old origin/master-old  # 2git reset --hard $new_master_commit      # 3git push -f origin                       # 4
  1. 首先在origin存储库中创建master-old分支,基于本地存储库中的master提交。
  2. 为这个新的origin/master-old分支创建一个新的本地分支(它将自动正确设置为跟踪分支)。
  3. 现在将您的本地master指向您希望它指向的任何提交。
  4. 最后,在origin存储库中强制更改master以反映您的新本地master

(如果您以任何其他方式执行此操作,则至少还需要一个步骤来确保正确设置master-old以跟踪origin/master-old。在撰写本文时发布的其他解决方案都不包括此。)

在服务器上登录,转到Git目录并在裸存储库中重命名分支。

这并没有重新上传同一分支的所有问题。实际上,“客户端”会自动识别修改后的名称并更改其远程引用。

之后(或之前)您还可以修改分支的本地名称。

当我尝试时,选择答案失败了。它抛出一个错误:refusing to delete the current branch: refs/heads/master。我想我会发布适合我的方法:

git checkout master             # If not in master already
git branch placeholder          # Create placeholder branchgit checkout placeholder        # Check out to placeholdergit push remote placeholder     # Push placeholder to remote repository
git branch -d master            # Remove master in local repositorygit push remote :master         # Remove master from remote repository.

诀窍是在将占位符推送到远程存储库之前签出占位符。其余的是不言自明的;删除主分支并将其推送到远程存储库现在应该可以工作了。摘自这里

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

在删除old-branch-name之前,您可能需要手动切换到new-branch-name

使用Git v1.7,我认为这略有改变。将本地分支的跟踪引用更新到新的远程现在非常容易。

git branch -m old_branch new_branch         # Rename branch locallygit push origin :old_branch                 # Delete the old branchgit push --set-upstream origin new_branch   # Push the new branch, set local branch to track the new remote

重命名分支的方法有很多,但我将重点关注更大的问题:“如何让客户端快进,而不必在本地弄乱他们的分支机构”

先看一张图片:重命名主分支并允许客户端快进

这实际上很容易做到;但不要滥用它。整个想法取决于合并提交;因为它们允许快进,并将分支的历史与另一个分支链接起来。

重命名分支:

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

创建新的“master”分支:

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

创建合并提交以具有父子历史记录:

# 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

瞧。

git push origin master

这是有效的,因为创建merge提交允许快进分支到新版本。

使用合理的合并提交消息:

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 obsoletesthe branch.
these are the steps I did:
git branch -m master master-oldgit branch master ba2f9ccgit checkout mastergit merge -s ours master-old

我相信关键是意识到你正在执行双倍重命名:mastermaster-oldmaster-newmaster

从所有其他答案中,我综合了这一点:

doublerename master-new master master-old

我们首先必须定义doublerename Bash函数:

# doublerename NEW CURRENT OLD#   - arguments are branch names#   - see COMMIT_MESSAGE below#   - the result is pushed to origin, with upstream tracking info updateddoublerename() {local NEW=$1local CUR=$2local OLD=$3local 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 haveto perform a Rebase Recovery."
git branch --move $CUR $OLDgit branch --move $NEW $CUR
git checkout $CURgit merge -s ours $OLD -m $COMMIT_MESSAGE
git push --set-upstream --atomic origin $OLD $CUR :$NEW}

这类似于更改历史记录的git rebase,因为分支内容完全不同,但不同之处在于客户端仍然可以安全地快进git pull master

好的,重命名当地的远程上的分支非常容易!…

如果你在树枝上,你可以很容易地做到:

git branch -m <branch>

如果没有,你需要:

git branch -m <your_old_branch> <your_new_branch>

然后,像这样将删除推送到远程:

git push origin <your_old_branch>

现在你完成了。

如果您在尝试推送时遇到上游错误,只需执行以下操作:

git push --set-upstream origin <your_new_branch>

我还创建了下面的图像来显示真实命令行上的步骤。只需按照步骤操作,你就会很好:

在此输入图片描述

您可以执行以下操作:

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

但是,如果其他人共享此存储库,则强制推送是一个坏主意。强制推送将导致他们的修订历史与新历史冲突。

这是我所知道的最简单和最“可读”的方式:

使用-m移动本地分支

git branch -m my_old_branch_name my_new_branch_name

将“移动”分支推送到远程,使用-u设置“上游”

git push origin -u my_new_branch_name

设置“上游”实际上是将您的本地分支“连接”到远程分支,以便获取、拉取和推送等操作可以正常工作。

从远程删除旧分支

git push origin -D <old_name>

你的本地分支已经消失了,因为你在第一步“移动”了它。

可以将以下内容保存到外壳脚本中以执行此操作:

例如:

remote="origin"
if [ "$#" -eq 0 ] # if there are no arguments, just quitthenecho "Usage: $0 oldName newName or $0 newName" >&2exit 1elif[ "$#" -eq 1 ] # if only one argument is given, rename current branchthenoldBranchName="$(git branch | grep \* | cut -d ' ' -f2)" #save current branch namenewBranchName=$1elseoldBranchName=$1newBranchName=$2fi
git branch -m $oldBranchName $newBranchName
git push $remote :$oldBranchName # Delete old branch on remotegit push --set-upstream $remote $newBranchName # Add new branch name on remote and track it

请注意,这里的默认远程名称“起源”是硬编码的。您可以扩展脚本以使其可配置!

然后,此脚本可以与Bash别名、Git别名或源树自定义操作一起使用。

转到github.com或任何地方,单击分支并重命名它。然后在本地运行这些:

git branch -m <old-branch-name> <new-branch-name>git fetch origingit branch -u origin/<new-branch-name> <new-branch-name>

2022年更新的解决方案

GitHub现在正式支持其用户重命名分支并在github文档上提供指南。

我已经按照他们的步骤成功地重命名了我的本地和远程分支。

如果URL被破坏,这里有解决方案。

重命名远程分支

  1. 在GitHub.com,导航到存储库的首页
  2. 在文件列表上方,单击分支输入图片描述
  3. 在分支列表中,要重命名的分支的右侧,单击编辑符号。输入图片描述
  4. 键入分支的新名称并查看信息,然后单击Rename分支输入图片描述

在分支名称更改后更新本地克隆

根据GitHub Docs:

在GitHub上重命名存储库中的分支后,任何具有存储库本地克隆的协作者都需要更新克隆。

从计算机上存储库的本地克隆,运行以下命令更新默认分支的名称:

$ git branch -m OLD-BRANCH-NAME NEW-BRANCH-NAME$ git fetch origin$ git branch -u origin/NEW-BRANCH-NAME NEW-BRANCH-NAME$ git remote set-head origin -a

或者,运行以下命令以删除对旧分支名称的跟踪引用:

$ git remote prune origin