主分支和'起源/主'已经发散,如何'解发散'分支'?

不知何故,我的master和我的origin/master分支出现了分歧。
我真的不想让他们分开。

我如何看待这些差异并合并它们?

1144211 次浏览

你可以审查差异

git log HEAD..origin/main
# old repositoriesgit log HEAD..origin/master

拉它之前(获取+合并)(另见“你如何让git总是从特定的分支中提取?”

注意:从Git 2.28(2020年第三季度)开始,默认分支是可配置的,现在(2021+)设置为main,不再是master
答案的其余部分反映了最近的惯例。


当您收到这样的消息时:

“您的分支和'起源/主'已经分歧,#并且分别有1个和1个不同的提交。

检查你是否需要更新#0
如果origin是最新的,那么当您在本地进行自己的提交时,一些提交已从另一个存储库推送到origin

... o ---- o ---- A ---- B  origin/main (upstream work)\C  main(your work)

您将提交C基于提交A,因为这是您当时从upstream获取的最新工作。

但是,在您尝试推回到origin之前,其他人推了提交B
发展历史已经分成不同的路径。

然后,您可以合并或重新定位。有关详细信息,请参阅Pro Git:Git分支-Rebasing

合并

使用git merge命令:

$ git merge origin/main
# old repositories$ git merge origin/master

这告诉Git将origin/main中的更改集成到您的工作中并创建合并提交。
历史的图表现在看起来像这样:

... o ---- o ---- A ---- B  origin/main (upstream work)\      \C ---- M  main (your work)

新的合并,提交M,有两个个父级,每个父级代表一条导致存储在该提交中的内容的开发路径。

请注意,M背后的历史现在是非线性的。

重新定位

使用git rebase命令:

$ git rebase origin/main
# old repositories$ git rebase origin/master

这告诉Git重放提交C(你的工作),就好像你基于提交B而不是A一样。
CVS和Subversion用户在提交之前更新时,通常会在upstream work之上重新构建他们的本地更改。
Git只是在提交和rebase步骤之间添加了明确的分离。

历史的图表现在看起来像这样:

... o ---- o ---- A ---- B  origin/main (upstream work)\C'  main (your work)

CommitC'是由git rebase命令创建的新提交。
它在两个方面与C不同:

  1. 它有一个不同的历史:B而不是A
  2. 它的内容占BC的变化;它与合并示例中的M相同。

请注意,C'后面的历史仍然是线性的。
我们选择(目前)只允许cmake.org/cmake.git中的线性历史。
这种方法保留了以前使用的基于CVS的工作流,并且可以简化过渡。
尝试将C'推送到我们的存储库中将起作用(假设您有权限并且在您重设时没有人推送)。

git pull命令提供了从originrebase本地工作到fetch的快捷方式:

$ git pull --rebase

这将上述fetchrebase步骤组合成一个命令。

我对此感到困惑,甚至在阅读了上面的回复之后,我也不知道是什么导致了它。我的解决方案是

git reset --hard origin/master

然后,它只是将我的(本地)master副本(我假设它被搞砸了)重置到正确的点,如(远程)源/master所示。

警告:您将丢失所有尚未推送到origin/master的更改。

git pull --rebase origin/master

是一个单一的命令,可以帮助你的大部分时间。

编辑:从源/主服务器提取提交,并将您的更改应用于新提取的分支历史记录。

在我的例子中,这是我为导致分歧消息所做的事情:我做了git push,然后做了git commit --amend向提交消息添加了一些东西。然后我还做了另一个提交。

所以在我的情况下,这仅仅意味着起源/主已经过时了。因为我知道没有其他人接触过起源/主,所以修复是微不足道的:git push -f(其中-f意味着力)

当我试图rebase一个跟踪远程分支的分支时,我发现自己处于这种情况,我试图将其重新定位在master上。在这种情况下,如果您尝试重新定位,您很可能会找到您的分支分歧,它可能会创建一个不适合git nubees的混乱!

假设你在分支my_remote_tracking_branch,它是从master分支出来的

$ git status

#在分支my_remote_tracking_branch

没有提交(工作目录清理)

现在你正在尝试从master重新定位为:

git rebase master

现在停止并为自己节省一些麻烦!相反,使用合并作为:

git合并大师

是的,你最终会在分支上获得额外的提交。但是,除非你准备使用“非发散”分支,否则这将是一个比rebase更流畅的工作流程。有关更详细的解释,请参阅这个博客

另一方面,如果您的分支只是当地分支(即尚未推送到任何远程),您肯定应该进行rebase(在这种情况下,您的分支不会分歧)。

现在,如果你正在阅读这篇文章,因为由于这样的重新定位,你已经在“发散”场景中了,你可以通过使用以下方法从源返回到最后一次提交(即处于未发散状态):

git重置-硬源/my_remote_tracking_branch

在我的情况下,这是因为我没有承诺解决冲突。

问题是由运行git pull命令引起的。源中的更改导致与我的本地存储库发生冲突,我解决了这个问题。但是,我没有提交它们。此时的解决方案是提交更改(git commit已解决的文件)

如果您在解决冲突后还修改了一些文件,git status命令将显示本地修改为非分阶段本地修改,并将合并解决方案显示为分阶段本地修改。这可以通过首先通过git commit提交合并中的更改,然后像往常一样添加和提交非分阶段更改(例如通过git commit -a)来正确解决。

在我的例子中,我已经将更改推送到origin/master,然后意识到我不应该这样做:-(本地更改在子树中这一事实使情况变得复杂。所以我回到“坏”本地更改之前的最后一次好的提交(使用SourceTree),然后我得到了“发散消息”。

在本地修复了我的混乱之后(这里的细节并不重要),我想“及时向后移动”远程origin/master分支,以便它再次与本地master同步。我的解决方案是:

git push origin master -f

注意-f(强制)开关。这删除了错误地推到origin/master的“错误更改”,现在本地和远程分支处于同步状态。

请记住,这是一个潜在的破坏性操作,因此只有在您100%确定及时“向后移动”远程主机是可以的情况下才能执行它。

查看差异:

git difftool --dir-diff master origin/master

这将显示两个分支之间的更改或差异。在araxy(我最喜欢的)中,它以文件夹差异样式显示它。显示每个更改的文件。然后我可以单击文件以查看文件中更改的详细信息。

我知道这里有很多答案,但我认为git reset --soft HEAD~1值得关注,因为它可以让你在解决发散状态的同时保留最后当地(未推送)提交的更改。我认为这是一个比rebase拉取更通用的解决方案,因为本地提交可以被审查,甚至移动到另一个分支。

关键是使用--soft,而不是苛刻的--hard。如果有超过1次提交,HEAD~x的变体应该可以工作。因此,以下是解决我的情况的所有步骤(我有1次本地提交和8次远程提交):

1)git reset --soft HEAD~1撤消本地提交。对于接下来的步骤,我使用了SourceTree中的接口,但我认为以下命令也应该有效:

2)git stash来隐藏从1)开始的更改。现在所有的更改都是安全的,不再有分歧了。

3)git pull获取远程更改。

如果需要,可以使用4)git stash popgit stash apply来应用上次隐藏的更改,然后是新的提交。当想要废弃本地提交中的更改时,此步骤和2)是可选的。此外,当想要提交到另一个分支时,此步骤应该在切换到所需分支后完成。

当我尝试编辑最后一条提交消息时,我收到了相同的消息,已经推送了提交,使用:git commit --amend -m "New message"当我使用git push --force-with-lease repo_name branch_name推送更改时没有问题

当我基于分支A创建分支时遇到了这个问题

git checkout -b a

然后我将分支A的上行流设置为原始分支B

git branch -u origin/B

然后我收到了上面的错误消息。

解决这个问题的一个方法是,

  • 删除分支a
  • 创建一个新的分支b
git checkout -b b origin/B

将123替换为您的分支偏离原始的提交数。

git reset HEAD~123 && git reset && git checkout . && git clean -fd && git pull

git复位--软原点/my_remote_tracking_branch

This way you will not loose your local changes

我更喜欢更方便、更安全的方式。

# copying your commit(s) to separate branchgit checkout <last_sync_commit>git checkout -b tempgit cherry-pick <last_local_commit>
git checkout mastergit reset --soft HEAD~1 # or how many commits you have only on local machinegit stash               # safer, can be avoided using hard resetting on the above linegit pullgit cherry-pick <last_local_commit>
# deleting temporary branchgit branch -D temp

我已经通过移动到commit_sha来修复它,最后一个是致力于起源/主。

git reset --hard commit_sha

警告:您将失去在“commit_sha”提交之后提交的所有内容。

我认为这应该帮助我:

git reset --hard origin/master

但它没有。不知何故,我收到了同样的消息&当我从远程分支拉取更改时,冲突就发生了。由于我确定我根本不需要现有的本地分支&我只需要远程分支master的副本,因此我想到了这个解决方案:

  • 签出到新分支,例如git checkout -b placeholder-branch。注意:稍后可以删除此分支。
  • git branch -D master,我这样做是因为我确信我的本地分支搞砸了&我不需要这个。我需要一个来自远程实例的新副本。
  • git checkout --track origin/master&你完成了;现在你可以使用git branch -D 删除placeholder-branch

要更直接地回答原始问题,您可以使用以下命令检查实际冲突的差异

git diff HEAD..origin/master

并使用此信息来决定是否将源的更改拉入本地存储库或将本地更改推送到源。

在我的情况下,当我将Xver1提交从分支B推送到其远程跟踪分支remote_B时,我收到了这条消息。然后在我的本地存储库上进行了更改并将其修改为相同的提交即。Xver2

现在我们在远程仓库上提交Xver1,在本地提交<强>Xver.2。然后git会向您显示警告

您的本地分支remote_分别有1个和1个不同的提交

要解决这个问题,你有两个选择:

1.pull远程跟踪分支的更改。

git reset --hard HEADgit checkout --track remoteRepoName/branch_name

2.force将修改后的提交推送到远程存储库。仅推荐在推X ver1提交后没有人拉取远程仓库的情况下

git push -f remote_repo_name remote_branch_name

您可能会遇到这种情况,只能从远程拉取1个历史记录:

$ git pull --depth=1fatal: refusing to merge unrelated histories$ git statusYour branch and 'origin/main' have diverged,and have 1 and 1 different commits each, respectively.

根据上面的答案,会导致两个分支发散到不同的“线”上,所以Git认为这是不相关的历史。

---a---b---main\      \x x x x   diverged, cannot be merged anymore\      \---?---?---?---c(origin/main)

最后,简单的解决方案是:git reset --hard origin/main,如果你不关心局部变化,否则,你将失去所有的工作。

尝试git pull --depth=2