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

Rename master branch for both local and remote Git repositories

我有一个分支master,它跟踪远程分支origin/master

我想在本地和远程将它们重命名为master-old。有可能吗?对于跟踪origin/master的其他用户(以及总是通过git pull更新本地master分支的用户),我重命名远程分支后会发生什么?他们的git pull还能工作吗,或者它会抛出一个错误,使它再也找不到origin/master了?

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

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


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

1
2
3
4
5
6
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

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

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

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


假设您目前在master上:

1
2
3
4
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
  • 首先,根据本地存储库中的master提交,在origin存储库中创建一个master-old分支。
  • 为此新的origin/master-old分支创建一个新的本地分支(将自动正确设置为跟踪分支)。
  • 现在将您的本地master指向您希望指向的任何承诺。
  • 最后,强制更改origin存储库中的master,以反映新的本地master
  • (如果您以任何其他方式进行此操作,则至少还需要一个步骤,以确保master-old正确设置以跟踪origin/master-old。在撰写本文时发布的其他解决方案都不包括这些。)


    对于Gitv1.7,我认为这有点变化。现在很容易更新本地分支对新远程的跟踪引用。

    1
    2
    3
    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


    1
    2
    git checkout -b new-branch-name
    git push remote-name new-branch-name :old-branch-name

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


    重命名分支有很多种方法,但我将重点关注更大的问题:"如何允许客户快速前进,而不必在本地处理他们的分支"。

    首先是一张简图:renaming master branch and allowing clients to fast-forward

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

    重命名分支:

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

    创建新的"主"分支:

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

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

    1
    2
    3
    4
    5
    6
    # 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

    还有。

    1
    git push origin master

    这是因为创建merge提交允许快速将分支转发到新的修订版。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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


    我假设你仍然在问与上一个问题相同的情况。也就是说,新大师不会在其历史中包含旧大师。*如果您将新大师称为"大师",您将有效地重写历史。你如何进入这样一种状态并不重要,在这种状态下,主人不是主人先前职位的后代,只是它处于那种状态。

    当master不存在时尝试拉的其他用户只会让他们的拉失败(在remote上没有这样的引用),一旦它再次存在于新位置,他们的拉将不得不尝试将其master与新的远程master合并,就像您在存储库中合并master old和master new一样。考虑到您在这里所要做的,合并将产生冲突。(如果解决了这些问题,并将结果推回到存储库中,那么您将处于更糟的状态—两个版本的历史都在那里。)

    简单地回答你的问题:你应该接受,有时候你的历史会有错误。这没关系。每个人都会这样。git.git存储库中存在已还原的提交。重要的是,一旦我们出版了历史,每个人都可以信任它。

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


    选择的答案在我尝试时失败。它抛出一个错误:refusing to delete the current branch: refs/heads/master。我想我会贴出适合我的东西:

    1
    2
    3
    4
    5
    6
    7
    8
    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.

    诀窍是在将占位符推送到远程存储库之前签出它。剩下的部分是不言而喻的,删除主分支并将其推送到远程存储库应该可以工作了。从这里摘录。


    很好。我的2美分。在服务器上输入loggin,转到git目录,并重命名裸存储库中的分支,怎么样?这并没有与重新绘制同一分支相关联的所有问题。实际上,"客户机"会自动识别修改后的名称并更改其远程引用。之后(或之前)您还可以修改分支的本地名称。


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

    "移动"本地分支使用-m

    1
    git branch -m my_old_branch_name my_new_branch_name

    将"已移动"分支推到远程,使用-u设置"上游"

    1
    git push origin -u my_new_branch_name

    (设置"上游"基本上是将本地分支连接到远程,这样诸如获取、拉和推之类的操作就可以工作)

    从远程删除旧分支

    1
    git push origin -D

    (您的本地分支已不存在,因为您在第一步"移动"了它)


    好的,在本地和远程重命名分支非常简单!…

    如果你在分支机构工作,你可以很容易地做到:

    git branch -m

    否则,您需要执行以下操作:

    git branch -m

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

    git push origin

    现在完成了,如果在尝试推送时出现上游错误,只需执行以下操作:

    git push --set-upstream origin

    我还创建了下面的图像来显示实际命令行中的步骤,只需遵循这些步骤,您就可以:

    enter image description here


    如何:

    1
    2
    3
    4
    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


    可以将以下内容保存到shell脚本以执行该作业:

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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

    请注意,这里默认的远程名称"origin"是硬编码的,如果可以配置的话,您可以扩展脚本使之成为可能!

    然后,该脚本可以与bash别名、git别名一起使用,或者在sourcetree自定义操作中使用。


    您可以执行以下操作:

    1
    2
    3
    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

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


    我认为关键是要认识到你正在执行双重重命名:mastermaster-oldmaster-newmaster

    从所有其他答案中,我综合了以下内容:

    1
    doublerename master-new master master-old

    我们首先要定义doublerenamebash函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    # 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
    }

    这类似于一个改变历史的git rebase,因为分支内容非常不同,但不同的是客户仍然可以安全地快速前进到git pull master


    1
    2
    git update-ref newref oldref
    git update-ref -d oldref newref