跳至内容
GitTree

课程 31 · 恢复

保持独立的工作并开始孤儿的历史

在离开之前,命名在分离的 HEAD 上所做的提交,然后在单独的副本中启动一个孤立分支,并查看它删除的内容和保留的内容。

进度已保存在此浏览器中。

播放时会加载来自 YouTube 的视频(隐私增强模式)。

英文旁白 · English and Arabic 字幕

打开视频页面在 YouTube 上观看

你将学到什么

  • 区分附着的、分离的和未出生的 HEAD。
  • 将分支放在分离的提交上,以便它保持可访问。
  • 预测孤立分支对跟踪文件、未跟踪文件和旧分支的作用。
  • 阅读因本地更改导致结账被拒绝的情况。

开始之前

第 18 课结果 M 的两个一次性副本。在第一个副本中,您检查提交 M 本身而不是分支,在那里进行一个小的样式表更改,并希望保留它。在第二种情况下,您需要纯文档分支的全新的、不相关的历史记录,而不需要触及 main。

一切都是本地的并且采用免费套餐(GitTree 要求您登录):没有托管帐户、没有提供商、没有互联网。每个身份都是虚构的(example.com)。切勿在实际项目中运行本课程。

在 GitTree 中或使用本机 Git 命令进行更改,而不是在同一副本中进行更改。读取结果总是安全的。菜单标签来自 GitTree 2.0 自己的字符串,本机命令使用 Git 2.43 在一次性副本中运行。 GitTree 步骤未在 macOS、Windows 或 Linux 上运行。

概念和状态效应

HEAD 通常命名一个分支,并提交移动该分支。当 HEAD 直接命名一个提交时,它是 detached:一个新的提交是真实的,但没有任何名称,因此切换离开后只能通过引用日志访问它。在上面放一根树枝就可以解决这个问题。除非您选择,否则创建分支不会切换到该分支。

orphan 分支是不同的。 HEAD 命名尚未提交的分支(未诞生的分支)。它的第一次提交没有父级,因此它不与 main 共享历史记录。 Git 从工作文件夹中删除跟踪的文件;未跟踪和忽略的文件会保留。如果旧的 .gitignore 被跟踪,它的规则也会随之变化,并且它忽略的文件现在可以显示为未跟踪。你的旧分支保留每一个提交。

这两种状态都是正常的,没有损坏。当结账会覆盖本地更改时会被拒绝;没有任何损失。

准备准确的项目状态

从第 18 课结果的两个单独的普通副本开始,并保持原件不变。下面的正文是基线样式表 (BASE_CSS)、加宽的样式表 (LAYOUT)、脏编辑 (DIRTY_LAYOUT)、孤立的自述文件 (ORPHAN_README)、本地注释 (LOCAL_NOTE) 和忽略的注释 (IGNORED_NOTE)。

完整的文件输入

仅在指定阶段保存每个完整的 UTF-8/LF 正文,并带有最后的换行符且没有 Markdown 栅栏。 BASE_CSS是继承的48rem引用; LAYOUT 是 52rem 提交; DIRTY_LAYOUT 是一个单独的未分级的 56rem 重播。这两个笔记文件仅属于幸存者变体。未更改的主文件继承完整的 L018/M 输入。

styles.css — BASE_CSS

文件摘录 · css
:root {
  color-scheme: light;
  --page: #f7f8fa;
  --surface: #ffffff;
  --text: #17212e;
  --link: #154ab5;
  --line: #bac4d0;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font: 1rem/1.6 system-ui, sans-serif;
}

a {
  color: var(--link);
}

.site-header,
main,
footer {
  width: min(68rem, 100% - 2rem);
  margin-inline: auto;
}

.site-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1rem;
}

.hero {
  max-width: 48rem;
  padding-block: 3rem;
}

h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: 1.2;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1rem;
}

.feature-card {
  padding: 1rem;
  border: 1px solid var(--line);
  border-radius: 0.75rem;
  background: var(--surface);
}

section {
  margin-block-end: 2rem;
}

button,
input {
  font: inherit;
}

button,
input {
  padding: 0.5rem 0.75rem;
}

:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
}

form {
  display: grid;
  max-width: 28rem;
  gap: 0.5rem;
}

styles.css — 布局

文件摘录 · css
:root {
  color-scheme: light;
  --page: #f7f8fa;
  --surface: #ffffff;
  --text: #17212e;
  --link: #154ab5;
  --line: #bac4d0;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font: 1rem/1.6 system-ui, sans-serif;
}

a {
  color: var(--link);
}

.site-header,
main,
footer {
  width: min(68rem, 100% - 2rem);
  margin-inline: auto;
}

.site-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1rem;
}

.hero {
  max-width: 52rem;
  padding-block: 3rem;
}

h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: 1.2;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1rem;
}

.feature-card {
  padding: 1rem;
  border: 1px solid var(--line);
  border-radius: 0.75rem;
  background: var(--surface);
}

section {
  margin-block-end: 2rem;
}

button,
input {
  font: inherit;
}

button,
input {
  padding: 0.5rem 0.75rem;
}

:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
}

form {
  display: grid;
  max-width: 28rem;
  gap: 0.5rem;
}

styles.css — DIRTY_LAYOUT

文件摘录 · css
:root {
  color-scheme: light;
  --page: #f7f8fa;
  --surface: #ffffff;
  --text: #17212e;
  --link: #154ab5;
  --line: #bac4d0;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font: 1rem/1.6 system-ui, sans-serif;
}

a {
  color: var(--link);
}

.site-header,
main,
footer {
  width: min(68rem, 100% - 2rem);
  margin-inline: auto;
}

.site-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1rem;
}

.hero {
  max-width: 56rem;
  padding-block: 3rem;
}

h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: 1.2;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1rem;
}

.feature-card {
  padding: 1rem;
  border: 1px solid var(--line);
  border-radius: 0.75rem;
  background: var(--surface);
}

section {
  margin-block-end: 2rem;
}

button,
input {
  font: inherit;
}

button,
input {
  padding: 0.5rem 0.75rem;
}

:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
}

form {
  display: grid;
  max-width: 28rem;
  gap: 0.5rem;
}

README.md — ORPHAN_README

输出
# GitTree Features documentation

This branch contains a documentation-only history for the fictional course project.
The landing page remains on main; no form submits information to a server.
Keep useful detached experiments under a branch name before switching away.

local-review.txt — LOCAL_NOTE

输出
Local rehearsal note; preserve this file.

reports/preview.txt — IGNORED_NOTE

输出
Ignored rehearsal preview; preserve these bytes.

在GitTree

使用 Command+Shift+P(在 Ubuntu 上为 Ctrl+Shift+P)打开调色板。

  1. 在第一个副本中,右键单击图表中的提交 M 并选择 Check Out This Commit。分支选择器显示“分离于...”并且图表显示 HEAD, detached。
  2. 将布局另存为 styles.css,暂存该文件并使用摘要 style: widen the hero reading measure 提交。当您工作时,面板会“在独立的 HEAD 上”计算变化。
  3. 右键单击新提交并选择 Create Branch Here…。将其命名为 experiment/layout,将检查选项保持关闭状态,然后选择 Create Branch。通知上写着“已创建实验/布局”。并且 HEAD 仍然分离。
  4. 右键单击 experiment/layout 标签并选择 Check Out Branch。 HEAD 再次附加,styles.css 是 LAYOUT,main 仍然指向 M。
  5. Dirty checkout. 在另一个副本中,在 experiment/layout 处分离,将 styles.css 编辑为 DIRTY_LAYOUT 而不提交,然后尝试签出 main。 “本地更改位于主程序中”对话框列出了该文件并提供了 Commit First、Stash and Switch 和 Discard and Switch。选择取消;丢弃会在 refs/ogt/trash 下保留一个副本,但这里不需要。
  6. Orphan. 在第二个副本中,使用干净的工作树,从选项板运行 Create Orphan Branch…。在“在……中创建一个孤儿分支?”输入 orphan-docs。该对话框指出有多少跟踪文件离开工作文件夹、保留未跟踪和忽略的文件以及旧提交保留在 refs/ogt/trash 下。取消具有焦点。选择Create Orphan Branch。
  7. 该通知显示“切换到新的孤立分支 orphan-docs。撤消切换回来。”该文件夹没有跟踪文件,并且图表显示新分支上没有提交。从 ORPHAN_README 创建 README.md,将其暂存并与摘要 docs: start the separate project guide 一起提交。新提交没有父提交。
  8. 比较:main 仍然有每个提交;孤儿分支是一个单独的根。不要推送任何一个副本。

对于课程中的每个普通提交:Summary 是规定的主题,Description 为空,并且选项 Amend Previous Commit、Skip Hooks、Add Signed-off-by、Different Author、Push After Commit 和 Allow Empty Commit 保持关闭状态。

在航站楼

在第一个副本中:

Command · bash
BASE_SHA="$(git rev-parse main)"
git switch --detach "$BASE_SHA"
git symbolic-ref --quiet --short HEAD; echo $?

最后一个命令打印 1: HEAD 不是分支。将 LAYOUT 保存为 styles.css,然后:

Command · bash
git commit --quiet -am "style: widen the hero reading measure"
git branch experiment/layout
git symbolic-ref --quiet --short HEAD; echo $?
git rev-parse HEAD^ main
git switch --quiet experiment/layout
git symbolic-ref --short HEAD
git status --short
输出
1
experiment/layout

创建命令不附加 HEAD(第二个查询仍然打印 1),来自 rev-parse 的两个 ID 相等(M),状态为空。在 experiment/layout 处分离的另一个副本中,编辑 styles.css 并运行 git switch main:Git 拒绝并显示“您对以下文件的本地更改将被签出覆盖”,并且文件未受影响。

在第二个副本中,有一棵干净的树:

Command · bash
git switch --orphan orphan-docs
git symbolic-ref --short HEAD
git rev-parse --verify --quiet HEAD; echo $?
git ls-files
输出
orphan-docs
1

该分支存在,但没有提交(rev-parse 退出 1)并且 ls-files 不打印任何内容。跟踪的文件将从文件夹中消失,而 local-review.txt 和 reports/ 保留并现在显示为未跟踪。创建 README.md,然后:

Command · bash
git add -- README.md
git commit --quiet -m "docs: start the separate project guide"
git ls-tree -r --name-only HEAD
git rev-list --max-parents=0 --count HEAD
git merge-base --all main orphan-docs; echo $?
输出
README.md
1
1

新分支有一个根提交,并且没有与 main 的共同祖先(merge-base 不打印任何内容并退出 1)。

结果

Where you end: 分离的提交名为 experiment/layout 并签出,main 仍然指向 M 并且树是干净的。孤立副本的 orphan-docs 具有一个没有父级的根提交,旧的跟踪文件已从文件夹中消失,但由 main 保留,并且没有推送任何内容。

常见错误

  • 提交分离的 HEAD 并在没有分支的情况下切换,这使得提交只能通过引用日志访问。
  • 预计 Create Branch Here… 切换到新分支。
  • 启动一个包含未提交的跟踪更改的孤立分支,或者认为它会删除 main。
  • 假设被忽略的文件在其 .gitignore 离开文件夹后仍然被忽略。

如果出现问题

如果您留下了一个没有名称的分离提交,请打开引用日志(第 29 课)并在其上放置一个分支。如果孤立分支出现错误,则 Undo 会在新分支没有提交时切换回来;否则请再次查看 main。结账被拒绝并没有改变什么。

检查你的理解情况

回答每个问题,然后阅读原因。标记为“必填”的问题将有助于完成本课程。

  1. 第 1 题,共 6 题

    什么是分离头?

    选择一个答案。

  2. 第 2 题,共 6 题

    关于孤儿分支,以下哪一项是正确的? (多选)

    选择每个适用的答案。

  3. 第 3 题,共 6 题
    必填

    您提交一个分离的 HEAD,在那里创建 experiment/layout 而不检查它,然后查看 HEAD。它是什么?

    选择一个答案。

  4. 第 4 题,共 6 题

    更改输入:当您尝试签出 main 时,工作树对 styles.css 进行了未提交的编辑。会发生什么?

    选择一个答案。

  5. 第 5 题,共 6 题
    必填

    git ls-files 在 git switch --orphan orphan-docs 之后不打印任何内容。有什么问题吗?

    选择一个答案。

  6. 第 6 题,共 6 题
    必填

    在 orphan-docs 上第一次提交后,哪些回读显示它是一个单独的根? (多选)

    选择每个适用的答案。

0 个(共 6 个)正确

正确回答所需的问题以完成课程。

在此浏览器中检查。

练习

报告 HEAD 在每个状态(分支、分离、未生成)中指向的位置、分离提交的 ID 及其上的分支,以及在孤立分支上打印的 git ls-files 内容。然后预测当 .gitignore 消失时被忽略的文件会发生什么。

您自己的确认:该网站无法看到您的计算机。

要完成本课程,请正确回答所需的问题并确认实践练习。

回顾

  • 分离的提交需要一个分支来保持可达性。
  • 孤立分支启动单独的根并从文件夹中删除跟踪的文件。
  • 拒绝结账可以保护您的编辑。

术语表介绍

分离的 HEAD — HEAD 删除;孤儿分支 — فря итим;未出生的分支 — فר ٺь فف; root 提交 — 详细信息。

视频文字记录

视频的旁白,逐条提示。

显示成绩单
  1. 头在哪里?三个状态。
  2. HEAD 可以命名分支、提交或 尚未提交的分支。
  3. 分离时所做的提交是真实的,但是 没有什么名字。
  4. 该提交上的分支保留它 可达。
  5. 右键单击提交 M,然后选择“检查” 出此提交。
  6. 更改样式表,暂存它,然后 提交一次。
  7. 右键单击新提交,然后创建一个 在这里分支,没有检查它。
  8. 现在检查一下分支。 HEAD 已连接 再次。
  9. 对于未保存的编辑,结帐是 拒绝了。取消保留一切。
  10. 首先提交,存储并切换,或者 丢弃。丢弃是要避免的。
  11. 对于新的历史记录,请运行 Create Orphan 从调色板分支。
  12. 它对离开的跟踪文件进行计数。 未被追踪和被忽视的会留下来。
  13. 确认。该文件夹没有跟踪文件。
  14. 添加自述文件并提交。这个提交有 没有父母。
  15. 在终端中,当以下情况时,symbolic-ref 退出 1: HEAD 已分离。
  16. 在未出生的分支上,对 HEAD 进行 rev-parse 失败。
  17. 提交后,merge-base发现没有 共同的祖先。
  18. 如果您离开时没有分支,则 reflog 仍然有。
  19. 做法:在每个状态下命名HEAD,然后 预测被忽略的文件。
  20. 接下来,推动后从错误中恢复。