192

在进行 git rebase 时,我经常难以弄清楚在解决冲突时“本地”和“远程”发生了什么。有时我的印象是他们从一个提交到下一个提交交换了双方。

这可能(肯定)是因为我还没有正确理解。

变基时,谁是“本地”,谁是“远程”?

(我使用 P4Merge 来解决冲突)

4

4 回答 4

272

TL;博士;

总结(如Benubird 评论),当:

git checkout A
git rebase   B    # rebase A on top of B
  • localB(变基),
  • remoteA

和:

git checkout A
git merge    B    # merge B into A
  • localA(并入
  • remoteB

一个变基切换ours(变基开始之前的当前分支)和theirs(要变基的分支)。


kutschkem指出,在 GUI 合并工具上下文中

  • 本地引用部分重新提交的提交:“ ours”(上游分支)
  • remote 指的是传入的更改:“ theirs” - 变基之前的当前分支。

请参阅此答案最后一部分中的插图。


变基时反转

混淆可能与rebase的反转ourstheirs期间有关。
(相关摘录)

git rebase手册页

请注意,rebase 合并的工作原理是从分支顶部的工作分支重放每个提交<upstream>

因此,当发生合并冲突时:

  • 报告为 ' ours' 的一侧是迄今为止重新调整的系列,以 ,<upstream>开头
  • ' theirs' 是工作分支。换句话说,双方交换了。

倒置说明

在合并中

x--x--x--x--x(*) <- current branch B ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

,我们不会更改当前分支“B”,所以我们所拥有的仍然是我们正在处理的(并且我们从另一个分支合并)

x--x--x--x--x---------o(*)  MERGE, still on branch B
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              their

在变基上:

但是在 rebase 上,我们切换到一边,因为 rebase 所做的第一件事就是检查上游分支!(在它之上重播当前的提交)

x--x--x--x--x(*) <- current branch B
    \
     \
      \--y--y--y <- upstream branch

Agit rebase upstream将首先将HEADB 更改为上游分支HEAD(因此与之前的“当前”工作分支相比,“我们的”和“他们的”的切换。)

x--x--x--x--x <- former "current" branch, new "theirs"
    \
     \
      \--y--y--y(*) <- upstream branch with B reset on it,  
                       new "ours", to replay x's on it

,然后变基将在新的“我们的”B 分支上重放“他们的”提交:

x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs
    \
     \
      \--y--y--y--x'--x'--x'(*) <-  branch B with HEAD updated ("ours")
               ^
               |
        upstream branch

注意:“上游”概念是从其中读取数据或添加/创建新数据的参考数据集(所有 repo 或像这里一样,分支,可以是本地分支)。


' local' 和 ' remote' vs. ' mine' 和 ' theirs'

Pandawood评论中补充道:

对我来说,问题仍然存在,即“本地”和“远程”谁(因为在 git 中重新定位时不使用“我们的”和“他们的”这两个术语,引用它们似乎会使答案更加混乱) .

GUI git 合并工具

kutschkem补充说,这是正确的:

解决冲突时,git 会说:

local: modified file and remote: modified file. 

我很确定这个问题针对的是本地和远程的定义。在这一点上,根据我的经验,在我看来:

  • 本地引用部分重新提交的提交:“ ours”(上游分支)
  • remote 指的是传入的更改:“ theirs” - 变基之前的当前分支。

git mergetool确实提到了“本地”和“远程”

Merging:
f.txt

Normal merge conflict for 'f.txt':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (kdiff3):

例如,KDiff3像这样显示合并分辨率

kdiff3

并且融合也会显示它

融合差异

VimDiff相同,它显示

使用 git mergetool -t gvimdiff 调用 Vimdiff 作为合并工具。最新版本的 Git 使用以下窗口布局调用 Vimdiff:

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL
    包含当前分支上文件内容的临时文件。
  • BASE:
    包含合并通用基础的临时文件。
  • REMOTE
    包含要合并的文件内容的临时文件。
  • MERGED
    包含冲突标记的文件。

Git 已尽可能多地执行自动冲突解决,并且该文件的状态是两者的结合,LOCAL并且REMOTE带有围绕 Git 无法自行解决的任何内容的冲突标记。
应该将mergetool解析结果写入此文件。

于 2010-06-16T09:37:15.950 回答
46

底线

git rebase

  • LOCAL = 你要变基的基础
  • REMOTE = 你正在向上移动的提交

git 合并

  • LOCAL = 您要合并的原始分支
  • REMOTE = 您要合并其提交的另一个分支

换句话说,LOCAL始终是原始的,而REMOTE始终是之前不存在的提交,因为它们正在被合并或重新基于顶部

证明给我看!

当然。不要相信我的话!这是一个简单的实验,您可以自己看看。

首先,确保您正确配置了 git mergetool。(如果你不这样做,你可能无论如何都不会阅读这个问题。)然后找到一个工作目录。

设置您的存储库:

md LocalRemoteTest
cd LocalRemoteTest

创建初始提交(使用空文件):

git init
notepad file.txt  (use the text editor of your choice)
  (save the file as an empty file)
git add -A
git commit -m "Initial commit."

在非主分支上创建提交:

git checkout -b notmaster
notepad file.txt
  (add the text: notmaster)
  (save and exit)
git commit -a -m "Add notmaster text."

在主分支上创建提交:

git checkout master
notepad file.txt
  (add the text: master)
  (save and exit)
git commit -a -m "Add master text."

gitk --all

此时您的存储库应如下所示:

具有基本提交和两个单提交分支的存储库

现在进行变基测试:

git checkout notmaster
git rebase master
  (you'll get a conflict message)
git mergetool
  LOCAL: master
  REMOTE: notmaster

现在进行合并测试。关闭您的合并工具而不保存任何更改,然后取消 rebase:

git rebase --abort

然后:

git checkout master
git merge notmaster
git mergetool
  LOCAL: master
  REMOTE: notmaster
git reset --hard  (cancels the merge)

您的结果应该与顶部显示的结果相同。

于 2014-05-02T18:41:38.873 回答
3

我没有完全理解您的问题,但我认为下图可以解决您的问题。(变基:远程存储库--->工作区)

http://assets.osteele.com/images/2008/git-transport.png

来源:我的 Git 工作流程

于 2010-06-16T07:50:01.717 回答
1

我也是,迷茫了很久,经常做出错误的决定,不得不重新开始。

免责声明:我不是 git 专家,所以如果这里有任何问题,请纠正我!

我想我已经意识到我的困惑是因为我对 rebase 的描绘与许多人绘制的不同。这里有两张通常用来描述变基的图:

  --1--2--3--4--5
     \
      6--7--8

进而

  --1--2--3--4--5--6--7--8

当然,这是绘制它的一种方式,但我对变基所发生的事情的感觉是:

  --1--2--3--4--5
                 \
                  6--7--8

这当然是完全一样的。但从“我们/他们”的角度来看,情况有所不同。在第二种情况下,感觉好像“我们”仍然“在”分支上(“6--7--8”),我们想从“主”那里获取更改。所以在这个世界上,“我们的”仍然是“分支”。这让我感到困惑。

但是在第一个“世界视图”中,我认为这是 Git 的视图,我们移动到 master(我们想要重新定位的提交),然后从那里我们依次选择分支上的每个提交并应用它们。所以“我们的”最初成为“主人” 56成功应用后,“我们的”是6,但实际上6'是“在”主:

  --1--2--3--4--5--6'
     \
      6--7--8

然后我们继续使用“7”。

因此,在合并中,您“处于”状态8并将两者组合成一个新的提交,但在 rebase 中,您移动到5并尝试将分支上的提交中的差异应用为那里的新提交。

因此,rebase 最终结果的“真实”画面应该是:

  --1--2--3--4--5--6'--7'--8'
     \
      6--7--8

在变基之后,你就在8'. 你的分支也是如此(我想!)。这可以(在我看来)可视化为:

  --1--2--3--4--5
     \ \
      6--7--8 6'--7'--8'
于 2020-09-18T08:02:23.693 回答