git rebase,跟踪“本地”和“远程”

发布于 2024-09-06 00:26:20 字数 169 浏览 5 评论 0原文

在进行 git rebase 时,我经常很难在解决冲突时弄清楚“本地”和“远程”发生了什么。我有时有一种印象,他们从一个承诺到下一个承诺都会交换立场。

这可能(肯定)是因为我仍然没有正确理解这个范式。

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

(我使用 P4Merge 来解决冲突。)

When doing a git rebase, I often have difficulty working out what is happening with the 'local' and 'remote' when resolving conflicts. I sometimes have the impression that they swap sides from one commit to the next.

This is probably (definitely) because I still don't properly understand the paradigm.

When rebasing, who is 'local' and who is 'remote'?

(I use P4Merge for resolving conflicts.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

格子衫的從容 2024-09-13 00:26:20

TL;博士;

总结一下(如 Benubird 评论),当:

git checkout A
git rebase   B    # rebase A on top of B
  • localB(变基< strong>onto),
  • 远程A

并且:

git checkout A
git merge    B    # merge B into A
  • 本地A(合并 into),
  • remoteB

A rebase 切换 ours(rebase 开始前的当前分支)和他们的 (要在其上变基的分支)。


kutschkem 指出,在 GUI mergetool 上下文中

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

请参阅本答案最后部分的插图。


变基时反转

混乱可能与 在变基期间我们的他们的反转
(相关摘录)

git rebase 手册页

请注意,变基合并的工作原理是重放 分支顶部工作分支的每个提交。

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

  • 报告为“ours”的一侧是迄今为止重新调整基数的系列,从 开始,
  • 并且“>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

在变基上:

但是在变基上,我们切换一边,因为变基所做的第一件事就是签出上游分支! (重放其上的当前提交)

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

git rebase upper 将首先将 B 的 HEAD 更改为上游分支 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

,然后 rebase 将在新的“我们的”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

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


本地”和“远程”与“我的”和“他们的

Pandawood 添加了 评论

对我来说,问题仍然存在,哪个是“本地”,谁是“远程”(因为在 git 中 rebase 时不使用术语“我们的”和“他们的”,引用它们似乎只是给出了答案更令人困惑)。

GUI git mergetool

kutschkem 添加,正确的是:

解决冲突时,git 会说:

local: modified file and remote: modified file. 

我很确定这个问题针对的是本地和远程的定义。那时,根据我的经验,我认为:

  • 本地引用部分重新定位的提交:“ours”(上游分支)
  • 远程引用传入的提交更改:“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

meld 也会显示它

Meld diff

VimDiff显示

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

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • 本地
    包含当前分支上文件内容的临时文件。
  • 基础
    包含合并的公共基础的临时文件。
  • 远程
    包含要合并的文件内容的临时文件。
  • 合并
    包含冲突标记的文件。

Git 已执行尽可能多的自动冲突解决,此文件的状态是 LOCALREMOTE 的组合,并包含 Git 无法执行的任何内容的冲突标记自行解决。
mergetool 应该将解析结果写入此文件。

TL;DR;

To summarize (As Benubird comments), when:

git checkout A
git rebase   B    # rebase A on top of B
  • local is B (rebase onto),
  • remote is A

And:

git checkout A
git merge    B    # merge B into A
  • local is A (merge into),
  • remote is B

A rebase switches ours (current branch before rebase starts) and theirs (the branch on top of which you want to rebase).


kutschkem points out that, in a GUI mergetool context:

  • local references the partially rebased commits: "ours" (the upstream branch)
  • remote refers to the incoming changes: "theirs" - the current branch before the rebase.

See illustrations in the last part of this answer.


Inversion when rebase

The confusion might be related to the inversion of ours and theirs during a rebase.
(relevant extracts)

git rebase man page:

Note that a rebase merge works by replaying each commit from the working branch on top of the <upstream> branch.

Because of this, when a merge conflict happens:

  • the side reported as 'ours' is the so-far rebased series, starting with <upstream>,
  • and 'theirs' is the working branch.
    In other words, the sides are swapped.

Inversion illustrated

On a merge

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

, we don't change the current branch 'B', so what we have is still what we were working on (and we merge from another branch)

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

On a rebase:

But on a rebase, we switch side because the first thing a rebase does is to checkout the upstream branch! (to replay the current commits on top of it)

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

A git rebase upstream will first change HEAD of B to the upstream branch HEAD (hence the switch of 'ours' and 'theirs' compared to the previous "current" working branch.)

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

, and then the rebase will replay 'their' commits on the new 'our' B branch:

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

Note: the "upstream" notion is the referential set of data (a all repo or, like here, a branch, which can be a local branch) from which data are read or to which new data are added/created.


'local' and 'remote' vs. 'mine' and 'theirs'

Pandawood adds in the comments:

For me, the question still remains, which is "local" and who is "remote" (since the terms "ours" and "theirs" are not used when rebasing in git, referring to them just seems to make an answer more confusing).

GUI git mergetool

kutschkem adds, and rightly so:

When resolving conflicts, git will say something like:

local: modified file and remote: modified file. 

I am quite sure the question aims at the definition of local and remote at this point. At that point, it seems to me from my experience that:

  • local references the partially rebased commits: "ours" (the upstream branch)
  • remote refers to the incoming changes: "theirs" - the current branch before the rebase.

git mergetool does indeed mention 'local' and 'remote':

Merging:
f.txt

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

For instance, KDiff3 would display the merge resolution like so:

kdiff3

And meld would display it too:

Meld diff

Same for VimDiff, which displays:

Invoke Vimdiff as a mergetool with git mergetool -t gvimdiff. Recent versions of Git invoke Vimdiff with the following window layout:

+--------------------------------+
| LOCAL  |     BASE     | REMOTE |
+--------------------------------+
|             MERGED             |
+--------------------------------+
  • LOCAL:
    A temporary file containing the contents of the file on the current branch.
  • BASE:
    A temporary file containing the common base for the merge.
  • REMOTE:
    A temporary file containing the contents of the file to be merged.
  • MERGED:
    The file containing the conflict markers.

Git has performed as much automatic conflict resolution as possible and the state of this file is a combination of both LOCAL and REMOTE with conflict markers surrounding anything that Git could not resolve itself.
The mergetool should write the result of the resolution to this file.

北城孤痞 2024-09-13 00:26:20

底线

git rebase

  • LOCAL = 您要变基的基础
  • REMOTE = 您要在顶部

git 上移动的提交merge

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

换句话说,LOCAL 始终是原始分支,REMOTE< /strong> 总是那些以前没有提交过的人,因为它们正在被合并或重新基于顶部

证明它!

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

首先,确保 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."

在一个分支上创建一个提交不是 master:

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

在 master 分支上创建提交:

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

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

git rebase --abort

然后:

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

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

The bottom line

git rebase

  • LOCAL = the base you're rebasing onto
  • REMOTE = the commits you're moving up on top

git merge

  • LOCAL = the original branch you're merging into
  • REMOTE = the other branch whose commits you're merging in

In other words, LOCAL is always the original, and REMOTE is always the guy whose commits weren't there before, because they're being merged in or rebased on top

Prove it!

Certainly. Don't take my word for it! Here's an easy experiment you can do to see for yourself.

First, make sure you have git mergetool configured properly. (If you didn't, you probably wouldn't be reading this question anyway.) Then find a directory to work in.

Set up your repository:

md LocalRemoteTest
cd LocalRemoteTest

Create an initial commit (with an empty file):

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."

Create a commit on a branch that isn't master:

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

Create a commit on the master branch:

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

gitk --all

At this point your repository should look like this:

Repository with a base commit and two one-commit branches

Now for the rebase test:

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

Now the merge test. Close your mergetool without saving any changes, and then cancel the rebase:

git rebase --abort

Then:

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

Your results should be the same as what's shown up top.

糖果控 2024-09-13 00:26:20

我也曾经迷茫过很长一段时间,经常做出错误的决定,不得不重新开始。

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

  --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”),并且我们想要从“master”那里获取更改。所以在这个世界上“我们的”仍然是“枝条”。这就是让我困惑的地方。

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

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

然后我们继续对“7”进行同样的处理。

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

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

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

在 rebase 之后,您位于 8'。你的分支也是如此(我想!)。这可以想象为(在我看来):

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

I too, was confused for a long time, often making the wrong decision and had to start over.

I think I have come to the realization that my confusion was because I pictured a rebase differently than what many draw it. Here are two drawings that commonly are used to describe a rebase:

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

and then

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

And of course that is one way to draw it, but my feeling of what is happening with a rebase is this:

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

Which of course is exactly the same. But from an "ours/theirs" perspective it is different. In the second case it feels as if "we" are still "on" the branch ("6--7--8") and we want to pick up the changes from the "master". So in this world "ours" is still the "branch". And this is what confused me.

But in the first "world view", which I suppose is Git's view, we move to the master (the commit we want to rebase onto) and from there we pick each of the commits on the branch in turn and apply them. So "ours" becomes the "master", initially 5. After 6 has been applied successfully, "ours" is the 6, but actually the 6' that is "on" the master:

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

And then we go on for the same with the "7".

So in a merge you "are on" the 8 and combine the two into a new commit, but in a rebase you move to the 5 and try to apply the diffs in the commits on the branch as new commits there.

So the "true" picture of the end result of a rebase should really be:

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

And after the rebase you are on 8'. And so is you branch (I think!). And this could be visualized (in my mind) as:

  --1--2--3--4--5
     \           \
      6--7--8     6'--7'--8'
行至春深 2024-09-13 00:26:20

让我看到这个页面的是需要了解 git 树中的哪个 SHA 是我们的 / 基础 / 他们的(或 LOCAL / BASE / REMOTE )。

接受的答案,7年来的累积工作是惊人的,并且非常有帮助。
然而,我发现它缺少我正在寻找的有利位置。

当合并冲突变得严重时(尤其是由 Visual Studio 管理的 XML 文件,尤其是 .dtsx 文件),我希望能够轻松比较普通版本。

阅读答案后,我对所看到的内容有了更好的理解,但是如何识别我正在比较的提交/分支?我想要合并之前文件(或分支)的 SHA,位于我所在的变基位置。

首先,我了解了 ls-files --stage 以及每个状态如何具有一个直接 SHA (有关更多信息,请参阅我提供的这个答案

但这并不能帮助我理解涉及哪些提交- 尤其是当 rebase 超过了几个深度的承诺时。

然后我了解了 .git/rebase_merge 目录及其内容。

使用以下 git 别名,您可以获得 rebase 的每个 BASE、LOCAL 或 REMOTE 提交的 SHA:

git config --global alias.get-rebase-BASE-sha '!cat .git/rebase-merge/stopped-sha"'
git config --global alias.get-rebase-LOCAL-sha '!echo "REBASE_HEAD"'
git config --global alias.get-rebase-REMOTE-sha '!git rev-parse "$(cat .git/rebase-merge/stopped-sha)~1"'

这允许我执行诸如 * 之类的操作:

git restore $(git get-rebase-BASE-sha) -- FILE

* 虽然,这不是最方便的方法(请参阅此相关答案 - 与上面提到的相同 - 有关更多选项),这个将即使在 git add

或之后也能工作

git difftool $(git get-rebase-REMOTE-sha) $(git get-rebase-BASE-sha)

What got me to this page is the need to understand which SHA in the git tree is ours / base / theirs ( or LOCAL / BASE / REMOTE ).

The accepted answer, a cumulative work across 7 years is amazing, and is very helpful.
However, I found it was missing the vantage point I was looking for.

When a merge conflict goes bad (happens to me a lot with XML files managed by Visual Studio - .dtsx files in particular), I would like to be able to compare vanilla versions easily.

After reading the answer, I have a better understanding of what I'm seeing, but how do I identify the commit/branch I'm comparing with? I wanted the SHA of the files (or the branches) before the merge, in the position of the rebase I'm in.

First I learned about ls-files --stage and how each state has a direct SHA (for more on this, see this answer I provided)

But this didn't help me understand which commits are involved - especially when a rebase is more than a couple commits deep.

Then I learned about .git/rebase_merge directory and it's content.

With the following git aliases, you can get the SHA of each of the BASE, LOCAL or REMOTE commits of a rebase:

git config --global alias.get-rebase-BASE-sha '!cat .git/rebase-merge/stopped-sha"'
git config --global alias.get-rebase-LOCAL-sha '!echo "REBASE_HEAD"'
git config --global alias.get-rebase-REMOTE-sha '!git rev-parse "$(cat .git/rebase-merge/stopped-sha)~1"'

This allows me to do things like*:

git restore $(git get-rebase-BASE-sha) -- FILE

* although, it's not the most convenient method (see this related answer - same as mentioned above - for more options), this one will work even after a git add

or

git difftool $(git get-rebase-REMOTE-sha) $(git get-rebase-BASE-sha)
×纯※雪 2024-09-13 00:26:20

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

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

来源:我的 Git 工作流程

I didn't get your problem exactly but I think the following diagram resolves your issue. (Rebase : Remote Repository ---> Workspace)

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

Source: My Git Workflow

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文