简体   繁体   English

如何放弃旧的Git Master,并将分支用作新的Master?

[英]How to abandon old Git Master, and use branch as new master?

We have a project where we at one time had to go back in Git history a bit and start a new branch (which we here will call "new_branch") from an old commit. 我们有一个项目,我们不得不一次回顾一下Git的历史,并从旧的提交开始创建一个新的分支(在这里我们称为“ new_branch”)。 Now, all development is happening in new_branch, and the old Master is useless after the point where the branch was made. 现在,所有开发都在new_branch中进行,并且在分支创建之后,旧的Master不再有用。 So now we have a situation that looks like this: 因此,现在我们遇到了如下情况:

C1 = Commit 1, C2 = Commit 2, etc.

            C1                       
             |                       
            C2                       
             |\                      
            C3 \                     
             |  \                    
            ...  \                   
             |    \                  
Master -->  C17    \                         
                    \                
                   C18               
                    |                        
                   ...               
                    |                
                   C37 <-- new_branch

So what I want to do now, is abandon (undo?) all the commits made in Master after the branching-off point, that is, C3 through C17. 因此,我现在想做的是放弃(撤消?)分支点(即C3至C17)之后在Master中所做的所有提交。 At least, that's what I think I want to do? 至少,这就是我我要怎么办? I mean, C3 through C17 are useless now, and if I could undo them then I can merge new_branch back into Master, to make Master useful again. 我的意思是,C3至C17现在已无用,如果我可以撤消它们,则可以将new_branch合并回Master,以使Master再次有用。

So my question is, is this the right approach to achieve my goal of being able to use Master again? 所以我的问题是,这是实现我再次使用Master的目标的正确方法吗? And which command (I use Git from the command line in Linux) should I use to undo the C3 through C17 commits? 以及应该使用哪个命令(在Linux的命令行中使用Git)撤消C3到C17的提交? This is a project for work, so it's very important that I get this right. 这是一个工作项目,因此正确理解这一点非常重要。

The most straightforward solution is simply to force push new_branch onto origin's master : 最直接的解决方案就是简单地将new_branch推送到原点的master

git checkout new_branch
git push -f master

Then fixup your local master in one of several ways: 然后使用以下几种方法之一修复本地master

  1. git reset --hard origin/master ( on branch master ) git reset --hard origin/master分支master
  2. git branch -D master ( not on branch master , pull again to get the updated one) git branch -D master不在分支master ,再次拉以获得更新的版本)

There's no need in this scenario to rebase existing master with the new_branch . 在这种情况下,无需使用new_branch对现有的master设置new_branch

This will (obviously) obliterate the existing master and replace it with the contents and history of new_branch . (显然)这将消除现有的master ,并将其替换为new_branch的内容和历史记录。 Be sure of your intent. 确保您的意图。


As Romain points out below, using git branch -f obviates the local fixup step: 正如Romain指出的那样,使用git branch -f消除了本地修复步骤:

git branch -f master new_branch && git push -f origin master

since it moves the branch pointer locally as well. 因为它也将分支指针移动到本地。


As with many git issues, there are many ways to solve this, and other answers may be just as viable. 与许多git问题一样,有很多方法可以解决此问题,其他答案可能同样可行。

There are two general approaches to doing this; 有两种一般的方法可以做到这一点; each has drawbacks, so it depends what's more important in your situation. 每个都有缺点,所以这取决于您所处的情况。 Each approach has variations as well, with smaller trade-offs... 每种方法也都有差异,但权衡较小。


The first approach is a history rewrite of master . 第一种方法是master的历史重写。 That simply means moving master in a way that removes from its history some commits that currently are part of its history. 这仅意味着以某种方式移动master ,从而从其历史中删除当前属于其历史的某些提交。

Any history rewrite has certain costs no matter how you do it - so it's usually best to do it the simplest way that meets your requirements. 无论您如何执行,任何历史记录重写都会产生一定的成本-因此,通常最好以最简单的方式来满足您的要求。 In this case, that's probably 在这种情况下,

git checkout master
git reset --hard new_branch
git push --force-with-lease

This is similar in effect to the approach msanford recommends, but has two advantages. 这实际上与msanford建议的方法相似,但是有两个优点。 First, it's a little more concise (in that it updates the local branch first and uses that as the setup for updating the rmeote). 首先,它更加简洁(因为它首先更新了本地分支并将其用作更新rmeote的设置)。 Secondly, replacing -f with --force-with-lease provides a little extra safety, in that it ensures the remote hasn't had anything new committed to it that you're unaware of. 其次,用--force-with-lease替换-f可以提供一些额外的安全性,因为它可以确保遥控器没有任何您不知道的新承诺。 (In your specific case, that probably isn't much of an issue; but it's a really good habit to get into.) (在您的特定情况下,这可能不是什么大问题;但这是一个很好的习惯。)

The cost of a history rewrite of a branch that has been shared across repos (ie push ed, and then - at least potentially - fetch ed or pull ed into other repos) is that other repos sharing the branch will see the branch move in an "unexpected" way and will have to recover. 对已在存储库之间共享的分支进行历史重写的成本(即, push ,然后(至少有可能)将其fetchpull入其他存储库)是共享该分支的其他存储库将看到该分支在一个存储库中移动。 “意外”的方式,将不得不恢复。 The recovery procedure is documented in the git rebase docs, in the section "recovering from upstream rebase". 恢复过程在git rebase文档的“从上游rebase恢复”部分中进行了说明。 It is important to coordinate with the entire team when doing this, as if any team member does the wrong thing when recovering, it can undo the history rewrite. 在进行此操作时,与整个团队进行协调非常重要,好像任何团队成员在恢复时做错了什么一样,都可以撤消历史记录的重写。

The upside is that you end with a very nice history that doesn't show the removed commits at all. 好处是,您的历史记录非常好,根本不会显示已删除的提交。 (Beware, though, that if those commits have been shared, nothing you can do ensures that they're "gone forever". If they contain sensitive information, that's a bigger problem and the information basically has to be considered compromised - though there are steps you can take to at least try to prevent further spread of such info.) (但是要注意,如果这些提交已被共享,则您无能为力,无法确保它们“永远消失”。如果它们包含敏感信息,那将是一个更大的问题,并且该信息基本上必须被视为已泄露-尽管存在您可以采取的步骤至少可以防止此类信息的进一步传播。)

So if you can practically coordinate with all users of the repo, this is a good way to go. 因此,如果您实际上可以与回购的所有用户进行协调,那么这是一个不错的方法。 But if you can't, there's another way. 但是,如果做不到,那是另一种方式。


The second approach is to undo the changes on master - ie revert it back to C2 - and then merge new_branch in. This conforms to the way branches are "supposed to" usually move, so doesn't carry the costs of a rewrite. 第二种方法是撤消对master的更改-即将其还原到C2然后合并new_branch 。这符合分支“应该”通常移动的方式,因此不承担重写的费用。 But, it means that the abandoned commits (and their reversal) remain forever in history. 但是,这意味着被遗弃的提交(及其撤消)在历史上将永远存在。

git checkout master
git revert -n C3..HEAD
git commit
git merge new_branch

This gives you a history like 这给你的历史像

C1 - C2 - C3 - ... - C17 - R -- M <--(master)
       \                       /
        C18 - ........... - C37 <--(new_branch)

R makes master look as it did at C2 , and M is a simple merge of the newer changes over that. R使得master的样子,因为它没有在C2 ,而M是超过了新的变化的简单合并。

If you omit the -n option from the revert command, you can skip the commit command, but you'll get a separate commit to undo each commit from C3 to C17 . 如果您从revert命令中省略了-n选项,则可以跳过commit命令,但是您将获得一个单独的提交,以撤消从C3C17每个提交。 There are also techniques for embedding the undoing-of-changes in the merge commit itself if you really feel strongly that this is better, but it creates an "evil merge" - a merge that hides changes and may confuse both users and certain future operations like git rebase . 如果您真的强烈认为这样做会更好,但也有一些技巧可以将更改的撤销嵌入到合并提交本身中,但是它会创建“恶意合并”,即隐藏更改并可能混淆用户和某些将来操作的合并像git rebase

The downside is a messier history. 不利的一面是混乱的历史。 (If you really need the history to document how you got where you are, then it is arguably more accurate; but it is certainly more complicated and shows information you may no longer need. It's certainly not suitable if the reverted commits contain sensitive information that you don't want to keep spreading.) (如果您确实需要历史记录来记录自己的位置,那么可以说它更准确;但是它肯定更复杂,并且可以显示您可能不再需要的信息。如果还原的提交包含敏感信息,则肯定不适合你不想继续传播。)

But, as noted above, it follows normal branch movement patterns, so avoids the costs of a history rewrite. 但是,如上所述,它遵循正常的分支移动模式,因此避免了重写历史记录的成本。

So again, it depends what's more important in your situation. 因此,这再次取决于您所处的情况。

so if you want to erase c3 - c17 you can checkout c3 and then put your new branch's changes on top of that using merge. 因此,如果您要删除c3-c17,则可以检出c3,然后使用merge将新分支的更改放在最上面。 Then if you push back up to master then c3 - c17 will be gone 然后,如果您将其推回主机​​,则c3-c17将消失

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM