题 使当前的Git分支成为主分支


我在Git中有一个存储库。我做了一个分支,然后对主人和分支做了一些改变。

然后,几十次提交之后,我意识到分支处于比主设备好得多的状态,所以我希望分支“成为”主设备并忽略主设备上的更改。

我无法合并它,因为我不想在master上保留更改。我该怎么办?

额外:在这种情况下,'旧'主人已经 push-ed到另一个存储库,如GitHub。这怎么改变了?


1312
2018-05-04 05:30


起源


检查非常相似问题的答案 stackoverflow.com/q/2862590/151641 - mloskot
有同样的问题,但我只是删除了主人并将另一个分支重命名为master: stackoverflow.com/a/14518201/189673 - jayarjo
@jayarjo如果可能的话,你应该避免这种情况,因为它会重写历史,并在下次尝试拉主人时给其他人带来问题。 - joelittlejohn
这就是为什么我喜欢@Jefromi的回答。没有解构档案的历史。 - froggythefrog


答案:


另外两个答案的问题是新主人没有旧主人作为祖先,所以当你推动它时,其他人都会搞砸了。这是你想要做的:

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

1745
2018-05-04 06:00



关于git的合并“策略”的注意事项: --strategy=ours 不同于 --strategy=recursive -Xours。即“我们的”可以是一个策略本身(结果将是当前分支,无论如何),或作为“递归”策略的选项传递(引入其他分支的更改,并在发生冲突时自动更喜欢当前分支的更改) 。 - Kelvin
我不得不做第二行 git merge --strategy=ours master -m "new master" 它的工作原理。 - incandescentman
@Johsm这正是我回答的第一句话所说的。如果您这样做,新主控器将不会具有与旧主控器相同的历史记录,如果您想要推/拉,则非常糟糕。你需要拥有共享的祖先才能正常工作;如果相反你做你所说的话,那么当你试图推动它时,除非你强迫它(因为这是坏的并且它试图阻止你),否则它将会失败,如果你强迫它,那么任何随后拉动它的人将尝试合并旧的主人和新的主人,这可能是火车残骸。 - Cascabel
如果出现合并期间的vi编辑器,请键入:w(用于保存):q(用于退出vi) - qub1n
这个答案很有效。我只想添加(对于可能是新的或不确定的人)你必须做的事情 git push 在此之后,如果您希望将代码推送到远程。您可能会看到类似的警告 Your branch is ahead of 'origin/master' by 50 commits. 这是预料之中的。推它吧! :d - chapeljuice


确保所有内容都被推送到远程存储库(GitHub):

git checkout master

用“better_branch”覆盖“master”:

git reset --hard better_branch

强制推送到远程存储库:

git push -f origin master

170
2018-06-24 20:25



这可能是大多数人都在寻找的答案。 BS策略合并的所有其他答案都不会完全取代分支。这使得一切都像我想要的那样,只需覆盖分支并推动它。 - Gubatron
虽然这确实是许多人正在寻找的,但应该注意的是,回购的任何其他本地副本都需要 git reset --hard origin/master 下次他们想拉,否则git会尝试将这些变化合并到他们(现在)发散的本地。更多的解释了这个的危险性 这个答案 - 7yl4r
同意!这是大多数人都在寻找的答案。 - Antuan
另请注意,您需要被允许强制推送到存储库 - 例如在商业环境中这不起作用 - inetphantom


编辑: 你没有说你曾经推动过公共回购!这让世界变得与众不同。

有两种方式,“脏”方式和“干净”方式。假设您的分支已命名 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

65
2018-05-04 05:37



谢谢。还有一个问题。我正在把它推向github。如果我这样做会在那里发生什么? - Karel Bílek
@Karel:这会给其他用户造成一些混乱;他们必须将他们的主人重置为github主人。如果你想避免给他们造成任何麻烦,请看看我的答案。 - Cascabel
@Dietrick Epp:我不确定是否建议肮脏的方式是个好主意。它会搞乱远程跟踪,reflogs ......想不出你曾经做过的任何理由。 - Cascabel
啊,这是一个好点。但是你可以两种方式: git branch old-master master; git branch -f master new-master。新建备份分支,然后直接将master移动到new-master。 (抱歉拼错了你的名字,只是注意到了) - Cascabel
@FakeName我没有得出结论,没有理由这样做,只是没有理由这样做 肮脏的方式。您可以使用普通命令(如我之前的评论中)执行此操作并获得相同的结果,除非reflog完好无损并且没有机会进行borking。并且它保证可以正常工作,因为您不会忽略实现细节。 - Cascabel


将分支重命名为 master 通过:

git branch -M branch_name master

40
2018-05-04 05:37



不幸的是,git不跟踪分支重命名,所以如果你已经将你的repo推送到远程,而其他人在他们的本地旧主分支上进行了本地更改,那么他们就会遇到麻烦。 - thSoft
这和之间有区别吗? git checkout master&&git reset --hard better_branch? - wotanii


这里给出的解决方案(在'master'中重命名分支)并不坚持远程(GitHub)repo的后果:

  • 如果你在制作那个分支后没有推动任何东西,你可以重命名它并毫无问题地推动它。
  • 如果你在GitHub上有push master,你需要'git push -f'新分支: 你不能再推进快进模式了
    -F
     - 力

通常,该命令拒绝更新远程ref,该远程ref不是用于覆盖它的本地ref的祖先。此标志禁用检查。这可能导致远程存储库丢失提交;小心使用它。

如果其他人已经撤回了你的仓库,他们将无法在没有用新的GitHub主分支替换他们自己的主仓(或处理大量合并)的情况下拉出新的主历史记录。
用于公共回购的git push --force的替代品
Jefromi的回答 (将正确的更改合并回原始主人)就是其中之一。


11
2018-05-04 05:57





据我所知,您可以将当前分支分支到现有分支。从本质上讲,这将覆盖 master 无论你在当前分支中拥有什么:

git branch -f master HEAD

一旦你完成了,你通常可以推动你的本地 master 分支,可能需要  参数在这里:

git push -f origin master

没有合并,没有长命令。只是 branch 和 push- 但是,是的, 这将改写历史 的 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

10
2018-04-04 22:44



很简单,工作得很完美!两个简单易懂的git命令。我的git repo已保存,现在看起来非常干净。谢谢! - thehelix


也可以将其他分支中的所有文件签出到master中:

git checkout master
git checkout better_branch -- .

然后提交所有更改。


6
2018-03-04 17:51





我发现这种简单的方法可以发挥最佳效果。它不会重写历史记录,并且分支的所有先前签入都将附加到主服务器。没有任何东西丢失,你可以清楚地看到提交日志中发生的事情。

目标:使“分支”的当前状态成为“主人”

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

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

在此之后,您的主服务器将是您上次提交分支的确切状态,您的主提交日志将显示该分支的所有签入。


5
2018-04-08 15:30





要添加到Jefromi的答案,如果你不想在历史上放置一个毫无意义的合并 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

这样合并提交只会存在于历史中 target 科。

或者,如果您根本不想创建合并,则只需抓取其中的内容即可 source 并使用它们进行新的提交 target

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>

3
2018-03-16 17:16