课程 23 · 恢复
解决合并和变基冲突
在合并和变基中解决相同的竞争标题,了解为什么“我们的”和“他们的”在它们之间交换,保存一个经过深思熟虑的组合结果,并在不丢失任何人的想法的情况下完成每一项操作。
- 级别: 中级
- 阅读 6 分钟
- 7 分钟的视频
- 已更新
- 在这节课之前: 合并具有不同历史记录的分支, 将未发表的作品重新建立到新的基础上
进度已保存在此浏览器中。
播放时会加载来自 YouTube 的视频(隐私增强模式)。
你将学到什么
- 读取真实的冲突:基地、当前方和传入方。
- 解释为什么“我们的”和“他们的”在合并和变基之间交换。
- 写下一项深思熟虑的决议,然后将其标记为已解决。
- 继续操作并检查是否有任何半途而废的情况。
开始之前
两个队友更改了页面的同一行。 conflict/sara,Sara 将主标题更改为“自信地审查更改”。在 conflict/omar,Omar 将同一行更改为“了解每个已保存的更改”。两个分支都从提交 M 开始,其中标题是“清楚地看到你的工作。”,并且每个分支只有一个提交。您为此分歧制作两份相同的副本:一份用于合并 (gittree-conflict-merge),一份用于变基 (gittree-conflict-rebase)。在这两种情况下,conflict/sara 都被签出并且工作树是干净的。没有合并或变基正在运行。
一切都是本地的并且采用免费套餐(GitTree 要求您登录):没有托管帐户、没有提供商、没有互联网。每个身份都是虚构的(example.com)。切勿在实际项目中运行本课程。
在 GitTree 中或使用本机 Git 命令进行更改,而不是在同一副本中进行更改。读取结果总是安全的。菜单标签来自 GitTree 2.0 自己的字符串,本机命令使用 Git 2.43 在一次性副本中运行。 GitTree 步骤未在 macOS、Windows 或 Linux 上运行。
概念和状态效应
内容冲突意味着 Git 无法自行选择一个结果:双方对同一行进行了不同的更改。 Git 停止并在索引中保留该文件的三个版本:第 1 阶段是公共基础,第 2 阶段是“我们的”,第 3 阶段是“他们的”。它还将冲突标记写入工作树中的文件中。删除编辑器中的标记不会解决 Git 的任何问题:只有当您保存结果并将其暂存时,文件才会被解析,这会返回阶段 0。
“我们的”和“他们的”是立场,而不是人。在合并中,您位于 Sara 的分支,因此我们的版本是 Sara 的版本(当前侧),而他们的版本是 Omar 的版本(传入侧)。在 Sara 到 Omar 的 rebase 中,Git 首先移动到 Omar 的分支,然后重放 Sara 的提交,因此我们的版本是 Omar 的版本(您要 rebase 的分支),而他们的版本是 Sara 的提交。 GitTree 在每个名称旁边打印角色,这样您就不必记住:合并中的“(当前)”和“(传入)”,变基中的“(变基到)”和“(您的提交)”。
正确的结果很少是一侧的。这里的预期决议是“充满信心地审查每个更改。”,这既不是萨拉的路线,也不是奥马尔的路线。使页面的所有其他行保持原样。将文件标记为已解决阶段您的结果; continue 是一个单独的步骤,用于完成合并提交或在 Omar 上重新创建 Sara 的提交。
当操作停止时,分支是操作离开的位置并且文件发生冲突。没有任何内容到达服务器。
准备准确的项目状态
做一个分歧,然后复制两次。从第 18 课留下的项目的单独普通副本开始,并保持原始的 gittree-features 不变。页面版本如下:MERGED 是共享库,SARA 和 OMAR 是两个竞争版本,RESOLVED 是您将保存的结果。
完整的文件输入
仅在下面指定的阶段保存。这些是完整的 UTF-8/LF 正文,最后有换行符;永远不要粘贴 Markdown 栅栏。未更改的可运行文件继承命名输入。单独变体中的版本不得覆盖原始版本。
index.html — 合并
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">See your work clearly.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>index.html — SARA
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Review changes with confidence.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>index.html — 奥马尔
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Understand each saved change.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>index.html — 已解决
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main" tabindex="-1">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Review each change with confidence.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
<section aria-labelledby="plans-title">
<h2 id="plans-title">Choose the workflow you need</h2>
<div class="cards">
<article class="feature-card">
<h3>Local Git</h3>
<p>Local Git workflows work without signing in.</p>
</article>
<article class="feature-card">
<h3>Connected workflows</h3>
<p>Provider integrations and Nour require Pro or an applicable trial.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>在GitTree
使用 Command+Shift+P(在 Ubuntu 上为 Ctrl+Shift+P)打开调色板。对指定分支的操作使用该分支的右键单击菜单。
- 如下一节所示构建两个副本。打开 gittree-conflict-merge,签出
conflict/sara。 - 右键单击
conflict/omar并选择 Merge conflict/omar into conflict/sara。在 Record it as 下选择 Always a merge commit。该对话框警告“将因 1 个文件中的冲突而停止”;选择Merge。合并停止,这是预期的结果。 - 横幅上写着“将冲突/omar 合并到冲突/sara”和“1 个冲突”,而 Continue 尚不可用:“首先解决 1 个冲突”。选择Resolve。
- 从 Conflicted files 打开
index.html。读取两侧 conflict/sara (current) 和 conflict/omar (incoming),并使用 Show Base 读取 Base (common ancestor)。 - 选择 Edit Output,将冲突的标题替换为
Review each change with confidence.并保留每隔一行。然后选择Save and Mark Resolved。删除标记并关闭文件是不够的。 - 返回横幅上,选择 Continue。如果提供了一条消息,请保留提议的消息。等待合并完成:新提交有两个父提交。
- 打开 gittree-conflict-rebase,签出
conflict/sara。右键单击conflict/omar并选择 Rebase conflict/sara onto conflict/omar。将 Options for this rebase 下的选项保留为关闭状态,然后选择 Rebase conflict/sara。它因冲突而停止。 - 选择 Resolve 并打开
index.html。双方现在是 conflict/omar (rebasing onto) 和 conflict/sara (your commit):角色交换了。执行相同的 Edit Output → Save and Mark Resolved,然后 Continue。 - 检查两个副本:文件等于“已解决”,没有留下任何冲突文件,并且没有显示横幅。将两个结果分开,不要推挤。
对于课程中的每个普通提交:Summary 是规定的主题,Description 为空,并且选项 Amend Previous Commit、Skip Hooks、Add Signed-off-by、Different Author、Push After Commit 和 Allow Empty Commit 保持关闭状态。
在航站楼
在第 18 课结果的单独干净副本中:
git switch --create conflict/sara
BASE_SHA="$(git rev-parse HEAD)"将 SARA 保存为 index.html,然后:
git add -- index.html
git -c user.name="Sara Lindqvist" -c user.email=sara@example.com commit --quiet -m "feat: Sara clarifies the hero"
git switch --quiet --create conflict/omar "$BASE_SHA"将 OMAR 保存为 index.html,然后:
git add -- index.html
git -c user.name="Omar Haddad" -c user.email=omar@example.com commit --quiet -m "feat: Omar explains the hero"
git switch --quiet conflict/saraBASE_SHA 是 M,在任一竞争提交之前。将此分歧制作两份干净的副本,一份用于合并,一份用于变基 (cd .. && cp -R gittree-features gittree-conflict-merge && cp -R gittree-features gittree-conflict-rebase)。在合并副本中:
git merge --no-ff --no-edit conflict/omar
git ls-files --unmerged
git show :2:index.html
git show :3:index.html合并以退出代码 1 停止,git ls-files --unmerged 列出三个条目,阶段 1、2 和 3。git show :2:index.html 是 Sara 的版本(我们的),:3: 是 Omar 的(他们的); :1: 是基础。将 RESOLVED 保存为 index.html,然后:
git add -- index.html
git -c core.editor=true merge --continue
git ls-files --unmerged
git status --short最后两个命令不打印任何内容。在未触及的变基副本中:
git rebase conflict/omar
git show :2:index.html
git show :3:index.html变基停止。现在,:2: 是 Omar 的版本,而 :3: 是 Sara 的版本:角色交换了。将 RESOLVED 保存为 index.html,然后:
git add -- index.html
git -c core.editor=true rebase --continue
git ls-files --unmerged
git status --short现在,两个文件都已解析,并且没有任何内容未合并。 core.editor=true 只接受该命令的现有提交消息;它不会更改您的编辑器设置。要保留已停止的操作而不进行解析,请使用 git merge --abort 或 git rebase --abort。
结果
Where you end: 合并副本有一个新提交,其中包含两个父项和组合标题;变基副本在奥马尔的提交上重新创建了萨拉的提交,并具有相同的组合标题。在这两种情况下,index.html 等于 RESOLVED,没有留下任何冲突条目,操作结束并且状态为干净。
常见错误
- 假设“我们的”始终意味着您自己的特征。这意味着 Git 站在哪一边,并且随着操作的不同而变化。
- 在阅读两个版本和文件的其余部分之前,先批发一侧(“全部”)。
- 删除冲突标记,但从不保存并将文件标记为已解决。
- 重复已经完成的合并或变基。
如果出现问题
如果停止看起来错误,则横幅中的 Abort… 会恢复操作开始时的状态,并放弃迄今为止所做的决议; GitTree 首先保留恢复快照。如果文件在编辑时发生更改,请使用 Compare 和 Use as Output 选项,而不是强制旧的保存。在替换之前保留草稿的副本。
检查你的理解情况
回答每个问题,然后阅读原因。标记为“必填”的问题将有助于完成本课程。
0 个(共 6 个)正确
正确回答所需的问题以完成课程。
在此浏览器中检查。
练习
使用 git show :2:index.html 和 git show :3:index.html 证明两个操作的阶段角色,然后保存相同的 RESOLVED 文件并完成每个操作。预测如果您盲目地在两份副本中都使用“我们的”,那么页面中会留下什么。
您自己的确认:该网站无法看到您的计算机。
要完成本课程,请正确回答所需的问题并确认实践练习。
回顾
- 我们和他们的角色取决于操作。
- 先保存并标记为已解决,然后继续。
- 之后检查整个文件和运行状态。
有关的
术语表介绍
冲突—— 冲突;基地 — 阿尔萨斯;我们的——恩斯吉塔娜;他们的——解决—— Наّ。
视频文字记录
视频的旁白,逐条提示。
显示成绩单
- 冲突不是错误。它是一个 问题只有你能回答。
- 两个人改了同一条线 相同的文件。
- 萨拉写了一个标题。奥马尔写道 另一个。两者都是从同一页开始的。
- Git 无法猜测哪一行获胜,所以它 停下来问你。
- 首先,建立Sara和Omar的分支, 和两份相同的副本。
- 在第一个副本中我们合并。在第二个中, 我们重新设定基础。
- 在 Sara 的分支上打开合并副本。
- 右键单击 Omar 的分支并选择其 合并命令。
- 对话框已经警告:这将停止 一个文件中存在冲突。
- 选择始终合并提交,然后选择合并 一次。正如预期的那样,它停止了。
- 横幅显示了一场冲突。继续是 尚不可用。
- 选择“解决”,然后打开index.html。
- 两侧:Sara 的分支是当前的, 奥马尔的来了。
- 展示基地揭示了共同的祖先, 任何更改之前的页面。
- 现在编辑输出。将标题替换为 一条刻意的线。
- 保存并标记为已解决。直到现在 Git 将文件视为已解决。
- 返回横幅上,选择继续。的 合并完成。
- 新提交有两个父母,并且 合并标题。
- 现在是 rebase 副本,也在 Sara 上 分支。
- 右键单击 Omar 的分支,然后重新设置基准 莎拉的树枝放在上面。
- 关闭这些选项,然后重新设置一次基准。它 因冲突而停止。
- 查看标签。现在奥马尔的分店是 我们重新建立基础的那个。
- Sara 的提交是正在重播的提交。 角色互换了。
- 相同的分辨率:编辑输出,然后保存 并标记为已解决,然后继续。
- Sara 的提交是在之上重新创建的 奥马尔的,标题相同。
- 在终端中,列出未合并的条目 停止合并。
- 第二阶段是我们的:萨拉的航向。舞台 三是他们的:奥马尔的。
- 在停止的变基中,第二阶段和第三阶段 反之亦然。
- 修复后,没有任何内容被取消合并,并且 状态为空。
- 合并副本的尖端有两个父级;的 rebase copy 的提示有一个。
- 更改输入:删除标记并 保存,但不标记已解决。
- Git 仍然看到三个阶段,所以继续 保持不可用状态。
- 卡住?中止将分支放回原来的位置 手术开始了。
- GitTree 首先保存恢复快照, 所以即使中止也是安全的。
- 永远不要从你面前的一侧夺取一切 阅读两个版本。
- 练习:证明两者的舞台角色 副本,然后完成两份。
- 接下来,继续、跳过或中止操作 那已经停止了。