课程 31 · 恢复
保持独立的工作并开始孤儿的历史
在离开之前,命名在分离的 HEAD 上所做的提交,然后在单独的副本中启动一个孤立分支,并查看它删除的内容和保留的内容。
- 级别: 中级
- 阅读 5 分钟
- 5 分钟的视频
- 已更新
- 在这节课之前: 创建一个功能分支并仅退役一次性引用, 使用 reflog 查找丢失的提交
进度已保存在此浏览器中。
播放时会加载来自 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
: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 — 布局
: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
: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)打开调色板。
- 在第一个副本中,右键单击图表中的提交 M 并选择 Check Out This Commit。分支选择器显示“分离于...”并且图表显示 HEAD, detached。
- 将布局另存为
styles.css,暂存该文件并使用摘要style: widen the hero reading measure提交。当您工作时,面板会“在独立的 HEAD 上”计算变化。 - 右键单击新提交并选择 Create Branch Here…。将其命名为
experiment/layout,将检查选项保持关闭状态,然后选择 Create Branch。通知上写着“已创建实验/布局”。并且 HEAD 仍然分离。 - 右键单击
experiment/layout标签并选择 Check Out Branch。 HEAD 再次附加,styles.css是 LAYOUT,main仍然指向 M。 - Dirty checkout. 在另一个副本中,在
experiment/layout处分离,将styles.css编辑为 DIRTY_LAYOUT 而不提交,然后尝试签出main。 “本地更改位于主程序中”对话框列出了该文件并提供了 Commit First、Stash and Switch 和 Discard and Switch。选择取消;丢弃会在refs/ogt/trash下保留一个副本,但这里不需要。 - Orphan. 在第二个副本中,使用干净的工作树,从选项板运行 Create Orphan Branch…。在“在……中创建一个孤儿分支?”输入
orphan-docs。该对话框指出有多少跟踪文件离开工作文件夹、保留未跟踪和忽略的文件以及旧提交保留在refs/ogt/trash下。取消具有焦点。选择Create Orphan Branch。 - 该通知显示“切换到新的孤立分支 orphan-docs。撤消切换回来。”该文件夹没有跟踪文件,并且图表显示新分支上没有提交。从 ORPHAN_README 创建
README.md,将其暂存并与摘要docs: start the separate project guide一起提交。新提交没有父提交。 - 比较:
main仍然有每个提交;孤儿分支是一个单独的根。不要推送任何一个副本。
对于课程中的每个普通提交:Summary 是规定的主题,Description 为空,并且选项 Amend Previous Commit、Skip Hooks、Add Signed-off-by、Different Author、Push After Commit 和 Allow Empty Commit 保持关闭状态。
在航站楼
在第一个副本中:
BASE_SHA="$(git rev-parse main)"
git switch --detach "$BASE_SHA"
git symbolic-ref --quiet --short HEAD; echo $?最后一个命令打印 1: HEAD 不是分支。将 LAYOUT 保存为 styles.css,然后:
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 --short1
experiment/layout创建命令不附加 HEAD(第二个查询仍然打印 1),来自 rev-parse 的两个 ID 相等(M),状态为空。在 experiment/layout 处分离的另一个副本中,编辑 styles.css 并运行 git switch main:Git 拒绝并显示“您对以下文件的本地更改将被签出覆盖”,并且文件未受影响。
在第二个副本中,有一棵干净的树:
git switch --orphan orphan-docs
git symbolic-ref --short HEAD
git rev-parse --verify --quiet HEAD; echo $?
git ls-filesorphan-docs
1该分支存在,但没有提交(rev-parse 退出 1)并且 ls-files 不打印任何内容。跟踪的文件将从文件夹中消失,而 local-review.txt 和 reports/ 保留并现在显示为未跟踪。创建 README.md,然后:
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。结账被拒绝并没有改变什么。
检查你的理解情况
回答每个问题,然后阅读原因。标记为“必填”的问题将有助于完成本课程。
0 个(共 6 个)正确
正确回答所需的问题以完成课程。
在此浏览器中检查。
练习
报告 HEAD 在每个状态(分支、分离、未生成)中指向的位置、分离提交的 ID 及其上的分支,以及在孤立分支上打印的 git ls-files 内容。然后预测当 .gitignore 消失时被忽略的文件会发生什么。
您自己的确认:该网站无法看到您的计算机。
要完成本课程,请正确回答所需的问题并确认实践练习。
回顾
- 分离的提交需要一个分支来保持可达性。
- 孤立分支启动单独的根并从文件夹中删除跟踪的文件。
- 拒绝结账可以保护您的编辑。
有关的
术语表介绍
分离的 HEAD — HEAD 删除;孤儿分支 — فря итим;未出生的分支 — فר ٺь فف; root 提交 — 详细信息。
视频文字记录
视频的旁白,逐条提示。
显示成绩单
- 头在哪里?三个状态。
- HEAD 可以命名分支、提交或 尚未提交的分支。
- 分离时所做的提交是真实的,但是 没有什么名字。
- 该提交上的分支保留它 可达。
- 右键单击提交 M,然后选择“检查” 出此提交。
- 更改样式表,暂存它,然后 提交一次。
- 右键单击新提交,然后创建一个 在这里分支,没有检查它。
- 现在检查一下分支。 HEAD 已连接 再次。
- 对于未保存的编辑,结帐是 拒绝了。取消保留一切。
- 首先提交,存储并切换,或者 丢弃。丢弃是要避免的。
- 对于新的历史记录,请运行 Create Orphan 从调色板分支。
- 它对离开的跟踪文件进行计数。 未被追踪和被忽视的会留下来。
- 确认。该文件夹没有跟踪文件。
- 添加自述文件并提交。这个提交有 没有父母。
- 在终端中,当以下情况时,symbolic-ref 退出 1: HEAD 已分离。
- 在未出生的分支上,对 HEAD 进行 rev-parse 失败。
- 提交后,merge-base发现没有 共同的祖先。
- 如果您离开时没有分支,则 reflog 仍然有。
- 做法:在每个状态下命名HEAD,然后 预测被忽略的文件。
- 接下来,推动后从错误中恢复。