ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

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

我想这一切都会带来很多麻烦。有没有一种干净的方法可以得到我想要的东西?还是我应该保留 master 并创建一个新分支 master-new 并继续在那里工作?

接受的答案中给出的配方确实适用于任何名称的分支,但由于(默认情况下)主分支在 Git 中的特殊角色,警告(如前所述)不适用。
@kynan:我想我不明白。哪些注意事项适用于 master 而不适用于其他分支?如果它是一个名为 xy 的分支并且其他人已经跟踪了该分支,那会有什么不同?
警告您通常无法删除远程主机。不过,这不适用于亚里士多德的答案,因此您可能希望将其标记为已接受的答案。您是对的,任何 git push -f 都会影响从任何远程跟踪分支进行 pull 的能力。
您可以创建一个新分支 master-old,它指向与前一个 master 分支相同的提交。然后,您可以通过使用 ours 策略执行 merge 来用新更改覆盖 master 分支。当远程不允许非快进更改时,执行合并工作。这也意味着其他用户不会强制更新。
@kynan master 仅在它是唯一现有的分支时才特别。一旦您拥有多个分支,所有分支都处于平等地位。

P
Peter Mortensen

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

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 默认不允许远程删除 master 分支。您可以通过在 remote 存储库上将 receive.denyDeleteCurrent 配置值设置为 warnignore 来覆盖此设置。否则,如果您准备好立即创建新主节点,请跳过 git push remote :master 步骤,并将 --force 传递到 git push remote master 步骤。请注意,如果您无法更改远程的配置,您将无法完全删除 master 分支!

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


分支只是一个(名称,哈希)对 - 仅此而已。分支上有 reflog,但这永远不会暴露给远程客户端。
在远程删除master之前,我会在远程创建master-old。我只是偏执。
下面亚里士多德的回答允许您在不删除主人的情况下做到这一点,所以我认为这更可取。
如果您可以使用 new-branch-nameold-branch-name 而不是 master/master-old,那将是明确且安全的,因此这是一个普遍的问题。
如果删除的分支(这里:master)没有被其他分支引用,git 可能会垃圾收集那个......好吧......“分支”上的所有提交。 - 一些 git瓷器命令触发垃圾收集。 – 因此:首先创建新名称(指向同一个提交),然后删除旧名称。
A
Aristotle Pagaltzis

假设您目前在 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

首先,根据本地存储库中的主提交,在源存储库中创建一个 master-old 分支。为这个新的 origin/master-old 分支创建一个新的本地分支(将自动正确设置为跟踪分支)。现在将您的本地 master 指向您希望它指向的任何提交。最后,强制更改原始存储库中的 master 以反映您的新本地 master。

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


我同意,这是比“答案”更好的答案,但是对于来这里只是重命名分支(不是明确地掌握)的人来说,第三步没有多大意义。
无论您是在 master 还是其他分支,这对答案绝对没有影响。这个问题的标题很糟糕,它询问的任务比只是重命名一个分支更复杂。
结果证明这是对我有用的解决方案。我试图用另一个分支替换 master 。我做了一个 git log -1 origin/what_i_want_as_new_master 来获取第 3 步的 $new_master_commit。在推送(第 4 步)之后,其他开发人员会拉取并收到消息“您的分支比 master 领先 295 次提交。”为了解决这个问题,我发送了一封电子邮件,让他们知道每次运行: git pull; git checkout some_random_branch; git 分支 -D 主;混帐拉; git结帐大师;基本上,他们需要删除他们的本地 master 并拉取新版本,否则他们在本地的错误位置。
您可以更轻松地做到这一点:假设他们已经在 master 上,那么他们只需执行 git fetch && git reset --hard origin/master 以强制他们的本地 masterorigin 上的相同。我已经记录了这一点,以及更复杂的情况,即您在 master 之上有想要保留的本地提交,在 stackoverflow.com/q/4084868
确保远程配置文件具有“denyNonFastforwards = false”,否则您将收到“remote: error:denying non-fast-forward refs/heads/master (you should pull first)”
E
Excalibur

使用 Git v1.7,我认为这已经发生了轻微的变化。更新本地分支对新远程的跟踪引用现在非常容易。

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

--set-upstream 的替代方法如下:将分支在本地重命名并在源上删除后,只需执行以下操作:git push -u --all
这不适用于 master 分支,因为 git 不允许您删除远程 master。
@AlexandreNeto 在这种情况下,您可以在第 2 行之前执行第 3 行,将默认分支设置为 new_branch,然后最终使用第 2 行删除远程 master
惊人的简单步骤。这是问题的最佳答案
删除远程分支 git push origin --delete old_branch 的可读性略高。
s
sigod
git checkout -b new-branch-name
git push remote-name new-branch-name :old-branch-name

您可能必须在删除 old-branch-name 之前手动切换到 new-branch-name


该解决方案的任何部分是否删除了本地旧分支名称,或者这是一个单独的练习?
我认为最后必须运行 git branch -d old-branch-name 以删除本地旧分支。
您只能通过一个命令推送更改:git push remote-name new-branch-name :old-branch-name
这种方式不会让你的 git 历史复杂化吗?因为您正在打开一个新分支,而不是重命名当前分支。
@androider 没有。git 中的分支是 a simple references
d
dnozay

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

https://i.stack.imgur.com/q91BO.png

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

重命名分支:

# 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 point
git 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 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

谢谢! git merge -s ours master-old 是其他答案遗漏的关键部分。此外,“容易做”并不意味着“容易理解或发现”,这似乎是大部分 git 的情况,但我离题了。
我喜欢这样一个事实,即没有提到删除,并且那些使用上游克隆的人的过渡是“无缝的”。谢谢!
如果 master 有您不想要 master-new 的更改,这是否有效?
C
Community

我假设您仍在询问与 previous question 中相同的情况。也就是说,master-new 在其历史中不会包含 master-old。* 如果您将 master-new 称为“master”,您将有效地重写历史。 如何进入一个 master 不是 master 先前位置的后代的状态并不重要,只是它处于那个状态。

其他用户在 master 不存在时尝试拉取只会让他们的拉取失败(远程上没有这样的 ref),一旦它再次存在于新的地方,他们的拉取将不得不尝试将他们的 master 与新的远程 master 合并,就像您在存储库中合并了 master-old 和 master-new 一样。鉴于您在这里尝试执行的操作,合并会产生冲突。 (如果它们被解决,并且结果被推回存储库,你将处于更糟糕的状态 - 两个版本的历史都在那里。)

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

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


是的,这是同一个问题,只是一个想法如何解决它。但即使我不做这个分支重命名,如果可能的话,我很有趣。我认为像“master”这样的引用只是对特定提交的引用。我真的不想改变任何历史。我想我只是将主参考指向另一个头。这也意味着,如果我以前使用过分支名称,我将永远无法再次使用它?
实际上,分支是 refs - 指向提交的指针。问题是,我们期望分支的负责人以特定的方式发展(即,总是快进)。从其他人的角度来看,在您的公共 repo 中移动一个分支与重写该分支的历史是一样的。它不再指向包含它过去的所有内容的提交。
P
Peter Mortensen

selected answer 在我尝试时失败了。它抛出一个错误:refusing to delete the current branch: refs/heads/master。我想我会发布对我有用的东西:

git checkout master             # If not in master already

git branch placeholder          # Create placeholder branch
git checkout placeholder        # Check out 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.

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


如果在远程端进行检查,它将在 git push remote :master 上失败 - 您将在错误日志行中看到“远程:错误:”作为前缀。
P
Peter Mortensen

登录服务器,进入Git目录,在裸仓库重命名分支。

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

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


我忘记了登录 github 服务器的凭据。任何有凭据的人:-P
P
Peter Mortensen

好的,在本地和远程重命名分支非常容易!...

如果你在分支上,你可以很容易地做到:

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>

我还创建了下面的图像以显示真实命令行上的步骤。只需按照以下步骤操作即可:

https://i.stack.imgur.com/wwjZF.jpg


您推送删除的建议无效,我需要运行此命令: git push origin --delete
H
Hannes Tydén

关于什么:

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

搞砸了分支跟踪 - 用户可能必须在本地修复他们的分支?
一个解释将是有序的。
P
Peter Mortensen

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

使用 -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>

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


R
Riyafa Abdul Hameed

您可以执行以下操作:

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

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


P
Peter Mortensen

以下内容可以保存到 shell 脚本中来完成这项工作:

例如:

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 自定义操作中使用。


P
Peter Mortensen

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

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

M
Martin Vidner

我相信关键是意识到您正在执行 double 重命名:mastermaster-old 以及 master-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 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 安全地快进。


d
dlamotte
git update-ref newref oldref
git update-ref -d oldref newref

这似乎对我不起作用,我得到: git update-ref trunk trunk2 fatal: trunk2: not a valid SHA1
一个解释将是有序的。