将当前 Git 分支变为主分支

2071

我在Git中有一个代码库。我创建了一个分支,然后对主干和分支都进行了一些更改。

然后经过数十次提交后,我意识到该分支比主干更好,所以我想让该分支“成为”主干并忽略主干上的更改。

我不能合并它,因为我不想保留主干上的更改。我该怎么办?

额外信息:在这种情况下,“旧”的主干已经被推送到其他存储库,如GitHub。这会改变什么吗?


3
请查看关于非常相似问题的答案,网址为https://dev59.com/s3E85IYBdhLWcg3wQxPG。 - mloskot
6
我曾经遇到同样的问题,不过我只是删除了主分支,将另一个分支重命名为master:https://dev59.com/questions/EWYq5IYBdhLWcg3wujDF#14518201 - jayarjo
13
如果可能的话,你应该避免这样做,因为它会重写历史并给其他人在下次尝试拉取主分支时带来问题。 - joelittlejohn
17个回答

2518

另外两个答案存在的问题是,新的主分支没有旧的主分支作为祖先,因此当你推送它时,其他人会混乱。以下是您要执行的操作:

git checkout better_branch
git merge --strategy=ours master    # keep the content of this branch, but record a merge
git checkout master
git merge better_branch             # fast-forward master up to the merge

如果您希望您的历史记录更加清晰,我建议在合并提交消息中添加一些信息,以使清楚地了解您所做的事情。将第二行更改为:

git merge --strategy=ours --no-commit master
git commit          # add information to the template merge message

32
关于 git 的合并“策略”说明:--strategy=ours--strategy=recursive -Xours 是不同的。也就是说,“ours” 可以作为一种独立的策略(无论如何都会得到当前分支的结果),或者作为 "recursive" 策略的选项(引入其他分支的更改,并在冲突时自动优先采用当前分支的更改)。 - Kelvin
11
为了使它起作用,我不得不将第二行改为 git merge --strategy=ours master -m "new master" - incandescentman
8
这句话的意思是如果你这样做了,新的主分支将没有与旧的主分支相同的历史记录,这对于推送/拉取来说非常糟糕。为了使其正常工作,你需要有共享的祖先。如果你按照你所说的那样做,那么当你尝试推送时,它将简单地失败,除非你强制执行(因为这是不好的,并且它正在阻止你),如果你强制执行,那么随后任何人拉取时都会尝试合并旧的主分支和新的主分支,这可能会造成灾难。 - Cascabel
4
如果在合并过程中出现vi编辑器,请输入:w(保存):q(退出vi)。 - Tomas Kubes
17
这个答案很好用。我只想补充一下(对于那些可能是新手或不确定的人),如果你想把你的代码推送到远程仓库,那么就需要在此之后执行git push命令。你可能会看到一个警告,如“Your branch is ahead of 'origin/master' by 50 commits.”这是正常现象,只需点击推送即可! :D - chapeljuice
显示剩余31条评论

699

确保将所有内容推送到您的远程仓库(GitHub):

git checkout main

使用"better_branch"覆盖"main"分支:

git reset --hard better_branch

强制推送到远程仓库:

git push -f origin main

134
这可能是大多数人正在寻找的答案。 所有其他使用 BS 策略合并的答案都没有完全替换分支。这使一切都像我想要的那样,只需覆盖该分支并强制推送即可。 - Gubatron
55
尽管这确实是许多人在寻找的内容,但需要注意的是,任何其他本地副本的仓库下次想要拉取时都需要 git reset --hard origin/master,否则 git 将尝试将更改合并到它们(现在)不同的本地副本中。这种情况的危险性在这个答案中有更详细的解释。 - 7yl4r
7
请注意,您需要被允许强制推送到存储库——例如,在商业环境中,这是行不通的。 - inetphantom
5
这里的优势也可能成为缺点,这取决于人们想要什么。如果你想彻底替换“主枝”的历史,改为采用其他分支的历史,那么这就是你的答案。 - b15
这绝对是最干净的解决方案。谢谢。 - Khal91
显示剩余6条评论

82

编辑:你没说过你已经推送到公共仓库!这可是天壤之别。

有两种方法,一种是“脏”的方式,另一种是“干净”的方式。假设你的分支名为new-master,这是干净的方式:

git checkout new-master
git branch -m master old-master
git branch -m new-master master
# And don't do this part.  Just don't.  But if you want to...
# git branch -d --force old-master

这将使配置文件更改以匹配重命名的分支。

您还可以采用“肮脏”的方式,不会更新配置文件。这有点像上面的操作...

mv -i .git/refs/new-master .git/refs/master
git checkout master

2
谢谢。还有一个问题。我正在将它推送到Github上。如果我这样做会发生什么? - Karel Bílek
3
@Karel:这会给其他用户带来一些麻烦,他们将不得不重置他们的主分支到 GitHub 主分支。如果你想避免给他们造成任何麻烦,请看看我的回答。 - Cascabel
7
@Dietrick Epp: 我不确定建议采用"肮脏方式"是否明智。这会干扰远程跟踪、引用日志等...我想不到任何理由来支持你这么做。 - Cascabel
2
啊,这个观点很好。你可以两种方式都实现:git branch old-master master; git branch -f master new-master。创建备份分支,然后直接将主分支移动到新的主分支。 (对于拼错你的名字,我感到抱歉,刚刚才注意到) - Cascabel
2
@FakeName,我并没有得出没有理由这样做的结论,只是没有必要以不干净的方式去做。你可以使用普通命令(如我以前的评论中所述)来完成相同的结果,但参考日志仍完好无损,而且没有搞砸的风险。而且这样做是有保障的,因为你不会干扰实现细节。 - Cascabel
显示剩余12条评论

49

通过以下方式将分支重命名为master

git branch -M branch_name master

14
很遗憾,Git 无法跟踪分支重命名,因此如果您已经将存储库推送到远程并且其他人在他们的旧主分支上有本地更改,则会有麻烦。 - thSoft
这个和 git checkout master && git reset --hard better_branch 有什么区别吗? - wotanii
@thSoft 如果只有我在使用这个代码库怎么办? - Nike

33

据我所知,您可以将当前分支分支到现有分支。本质上,这将使用当前分支中的内容覆盖master

git branch -f master HEAD

完成上述步骤后,你通常可以推送本地的 master 分支,可能也需要在此处使用 force 参数:

git push -f origin master

没有合并,也没有长命令。只需使用branchpush命令。但是,是的,这将重写master分支的历史记录,所以如果你在团队中工作,你必须知道自己在做什么。




或者,我发现你可以将任何分支推送到任何远程分支,所以:

# This will force push the current branch to the remote master
git push -f origin HEAD:master

# Switch current branch to master
git checkout master

# Reset the local master branch to what's on the remote
git reset --hard origin/master

非常简单,完美运行!两个简单易懂的Git命令。我的Git存储库已保存,现在看起来非常干净。谢谢! - thehelix
@thehelix,为什么在你发表评论时已经有更简单的高票解决方案可供选择,你还是选择了这个方案? - Nike

33

我在博客文章Replace the master branch with another branch in git中找到了我想要的答案:

git checkout feature_branch
git merge -s ours --no-commit master
git commit      # Add a message regarding the replacement that you just did
git checkout master
git merge feature_branch

基本上与Cascabel的回答相同。只是他们解决方案中的"选项"在上面的代码块中已经嵌入。

这样更容易找到。

我将其作为新答案添加,因为如果我以后需要此解决方法,我希望在一个代码块中拥有所有需要使用的代码。

否则,我可能会复制粘贴,然后在执行代码之后才发现应该更改的行 - 之后才阅读下面的详细信息。


1
注意:引用的博客文章(https://git.tutorialhorizon.com/2014/10/05/replace-the-master-branch-with-another-branch-in-git/)已不再可用。 - eppineda

16

我发现这种简单的方法效果最好。它不会重写历史记录,分支的所有先前提交将附加到主分支上。没有任何损失,您可以在提交日志中清楚地看到发生了什么。

目标:使当前“branch”的状态成为“master”

在分支上工作,提交并推送更改以确保本地和远程存储库是最新的:

git checkout master      # Set local repository to master
git reset --hard branch  # Force working tree and index to branch
git push origin master    # Update remote repository

完成后,您的主分支将与上一次提交所在的分支状态完全相同,并且您的主分支提交日志将显示该分支的所有检入记录。


14

这里提供的解决方案(在“主”分支中重命名分支)并不强制执行对远程(GitHub)仓库的后果:

  • 如果您在创建该分支后没有推送任何内容,则可以更改名称并推送,而不会出现任何问题。
  • 如果您已经在GitHub上推送了主分支,则需要使用“git push -f”命令推送新分支:您不能再以快进模式推送
    -f
    --force

通常,该命令会拒绝更新不是用来覆盖它的局部参考的祖先的远程参考。此标记禁用了检查。这可能导致远程存储库丢失提交;请谨慎使用。

如果其他人已经拉取您的存储库,则无法拉取新的主分支历史记录,除非将其自己的主分支替换为该新GitHub主分支(或处理大量合并)。
公共存储库的git push --force可替代方案
Jefromi的回答(将正确的更改合并回原始主分支)是其中之一。


13

你也可以将另一个分支的所有文件检出到主分支:

git checkout master
git checkout better_branch -- .

然后提交所有更改。


7

补充一下Cascabel的回答,如果您不想在source分支的历史记录中留下一个无意义的合并,您可以为ours合并创建一个临时分支,然后将其丢弃:

git checkout <source>
git checkout -b temp            # temporary branch for merge
git merge -s ours <target>      # create merge commit with contents of <source>
git checkout <target>           # fast forward <target> to merge commit
git merge temp                  # ...
git branch -d temp              # throw temporary branch away

这样合并提交将仅存在于目标分支的历史记录中。

或者,如果您根本不想创建合并,则可以简单地获取“源”内容并将其用于“目标”的新提交:

git checkout <source>                          # fill index with contents of <source>
git symbolic-ref HEAD <target>                 # tell git we're committing on <target>
git commit -m "Setting contents to <source>"   # make an ordinary commit with the contents of <source>

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