Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions progress.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
= Pro Git, 3rd Edition — Progress
:toc:

Working task list for the third edition, derived from the chapter-by-chapter
inventory in `REVISION_PLAN.md`. This file is edited by hand: mark a task done by
changing `[ ]` to `[x]`, and add new tasks — or whole new sections — as they come
up. The site's progress page renders this file directly, so keep the format:
`== Section title` headings with `* [ ]` checklist items under them.

== Project setup

* [x] Import the 2nd-edition sources as the starting point
* [x] Write the revision plan (`REVISION_PLAN.md`)
* [x] Build the line-level `master` -> `main` inventory (`book_master_to_main_inventory.md`)
* [x] Launch the project site — book reader, blog, history
* [x] Set up the cloud build/test environment for agents

== Policy decisions

These gate the cross-cutting sweeps; decide them first.

* [ ] Decide the `master` -> `main` rename policy (gates X1, ~602 renames)
* [ ] Decide how to represent example hashes: regenerate everything at SHA-256, or keep labeled SHA-1 legacy examples (gates X2)

== Cross-cutting sweeps

* [ ] X1 — `master` -> `main` across the book (see the inventory for the per-line breakdown)
* [ ] X1 — regenerate diagrams and screenshots that show a `master` branch
* [ ] X2 — SHA-1 -> SHA-256 default-hash pass (~31 files reference hashes)
* [ ] X3 — version framing: bump "written using Git version 2" to 3.x; reframe "since Git 2.23/2.27/2.28" notes as baseline behavior
* [ ] X4 — cover the `safe.bareRepository` and `safe.directory` security defaults
* [ ] X5 — forge/IDE screenshot refresh (Ch 4, Ch 6, Appendix A)

== Chapter 1 — Getting Started

* [ ] Update the headline SHA-1 passage in `what-is-git.asc` (X2)
* [ ] Refresh per-platform install steps in `installing.asc`
* [ ] Add the Rust toolchain requirement to "compile from source"
* [ ] Rewrite the default-branch subsection of `first-time-setup.asc` for a main-default world
* [ ] Note Git's maturation and the 3.0 transition in the history section

== Chapter 2 — Git Basics

* [ ] Normalize `restore`/`switch` as standard commands (drop the "new in 2.23" framing)
* [ ] Decide whether to teach `restore`/`switch` before `checkout`/`reset`
* [ ] Update the `pull.rebase` warning framing in `remotes.asc`
* [ ] Regenerate example hashes per the X2 policy
* [ ] Note the `main` and reftable defaults in `getting-a-repository.asc`

== Chapter 3 — Git Branching

* [ ] X1 sweep (101 renames — the heaviest concentration)
* [ ] Regenerate the branch diagrams in `diagram-source/`
* [ ] Revisit the branch-renaming discussion in `branch-management.asc` for a main-default world

== Chapter 4 — Git on the Server

* [ ] Demote Gitweb and `git daemon`; lead with modern self-hosting
* [ ] Add Gitea/Forgejo coverage
* [ ] Cover protocol v2; retire dumb HTTP
* [ ] Recommend Ed25519 keys in `generating-ssh-key.asc`
* [ ] Add a sidebar on reftable and SHA-256 hosting/interop implications
* [ ] Refresh screenshots (X5)

== Chapter 5 — Distributed Git

* [ ] X1 sweep (`contributing` 48 renames, `maintaining` 39)
* [ ] Contextualize the email-based workflow against PR-based norms

== Chapter 6 — GitHub

* [ ] Re-capture all screenshots (X5)
* [ ] Text pass for the current PR review UI, org settings, and account setup flows
* [ ] Scope decision on Actions, Codespaces, and the current review experience
* [ ] Default-branch language in examples (26 renames in `2-contributing`)

== Chapter 7 — Git Tools

* [ ] Add SSH commit/tag signing to `signing.asc` (plus `gpgsm` for X.509)
* [ ] Rework `replace.asc` — grafts are removed in 3.0
* [ ] Add the new `git history` command to `rewriting-history.asc`
* [ ] Lead `rewriting-history.asc` with `git filter-repo`; mark `filter-branch` deprecated
* [ ] Update `credentials.asc` for Git Credential Manager
* [ ] Add `git worktree` coverage
* [ ] Add `git sparse-checkout` coverage
* [ ] Evaluate `git range-diff`, `git replay`, `git bugreport`, `git diagnose` for coverage
* [ ] X1 sweep (147 renames — the highest chapter total)

== Chapter 8 — Customizing Git

* [ ] Add `safe.bareRepository` and `safe.directory` to `config.asc` (X4)
* [ ] Rewrite `init.defaultBranch` as default-is-main
* [ ] Note `--object-format` (SHA-256) and `extensions.refStorage` (reftable)
* [ ] Note removed config: `core.commentString=auto`, `core.preferSymlinkRefs=true`
* [ ] Consider `git for-each-repo` in the scripting material
* [ ] X1 sweep (`policy.asc` enforced-workflow example, 8 renames)

== Chapter 9 — Git and Other Systems

* [ ] Trim `git svn` coverage
* [ ] Demote the Mercurial and Perforce bridges to a short "bridges exist" section
* [ ] Verify the bridge tooling runs on modern Python
* [ ] X1 sweep (23+ renames in the Hg sections, 37 in `git-p4`)

== Chapter 10 — Git Internals

* [ ] Rewrite `objects`/`packfiles` with the object-format framing and the SHA-256 interop story
* [ ] Add reftable to `refs.asc` — the new default, and the why (case-collision, performance)
* [ ] Fold protocol v2 into `transfer-protocols.asc`
* [ ] Verify `maintenance.asc` against current `git maintenance`
* [ ] Add `commit-graph` and `multi-pack-index` to the performance story
* [ ] X1 sweep (70 renames)

== Appendices

* [ ] Appendix A: version/screenshot refresh for Sublime Text, Visual Studio, VS Code, JetBrains IDEs
* [ ] Appendix A: version-check the shell completion sections
* [ ] Appendix B: refresh binding versions (`libgit2`, `jgit`, `go-git`, `dulwich`)
* [ ] Appendix B: promote `go-git`; add per-library SHA-256 support notes
* [ ] Appendix C: add post-2.1 commands to the command index; note the 3.0 removals

== New material

* [ ] Dedicated "Git 3.0 / migrating to SHA-256" section
* [ ] Reftable explainer (pairs with the Ch 10 refs rewrite)
* [ ] Monorepo-scale material: sparse-checkout, partial clone, `scalar`, `git backfill`
* [ ] `git maintenance` + commit-graph as a first-class performance story

== Publication

* [ ] Redo the contributors list and dedication
* [ ] Final pass on the appendices (fastest to rot; do near publication)
* [ ] Watch for the LTS tag (the last 2.x before 3.0) and time the release to it
30 changes: 30 additions & 0 deletions site/src/content/blog/a-progress-page-for-the-third-edition.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: 'A progress page for the third edition'
description: 'Every task the third edition needs, tracked in one hand-edited file and rendered as a live progress page on this site.'
date: 2026-08-02
---

The third edition now has a **[progress page](../../blog/progress/)** — one place
to see everything the revision needs and how much of it is done, section by
section, with progress bars to match.

Behind it is a single file:
[`progress.asc`](https://github.com/progit/progit3/blob/main/progress.asc), a
plain AsciiDoc checklist at the root of the repository. It distills the
chapter-by-chapter inventory from
[`REVISION_PLAN.md`](https://github.com/progit/progit3/blob/main/REVISION_PLAN.md)
into concrete tasks: the policy decisions that gate everything else, the
book-wide sweeps like `master` → `main` and SHA-256, a section for every chapter
and appendix, and the brand-new material Git 3.0 calls for.

The file is the source of truth, and it is edited by hand. Checking a task off
means changing `[ ]` to `[x]`; adding a task means adding a line. When new work
turns up — and it will — it gets a new line or a new section, and the page picks
it up on the next build. Because it is standard AsciiDoc checklist syntax, the
same file renders as tick-boxes right in the repository on GitHub.

At the time of writing the counter sits at **5 of 75 tasks** — the project
scaffolding is done, and the writing is about to begin. Watch the bars fill in
on the [progress page](../../blog/progress/), and if you spot work that belongs
on the list, [`progress.asc`](https://github.com/progit/progit3/blob/main/progress.asc)
is one pull request away.
71 changes: 71 additions & 0 deletions site/src/lib/progress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Parse the repo-root progress.asc — a hand-edited AsciiDoc checklist — into
// structured data for the progress page. The file's contract is simple:
// `== Section title` headings with `* [ ]` / `* [x]` checklist items below.
// Anything else (the doc title, paragraphs, comments) is ignored.

import progressSrc from '../../../progress.asc?raw';

export interface Task {
text: string;
done: boolean;
/** 0 for `*` items, 1 for `**`, … */
depth: number;
}

export interface Section {
title: string;
tasks: Task[];
done: number;
total: number;
}

export interface Progress {
sections: Section[];
done: number;
total: number;
percent: number;
}

export function parseProgress(src: string): Progress {
const sections: Section[] = [];
let current: Section | null = null;

for (const line of src.split(/\r?\n/)) {
const heading = line.match(/^={2,3} +(.+?)\s*$/);
if (heading) {
current = { title: heading[1], tasks: [], done: 0, total: 0 };
sections.push(current);
continue;
}

const task = line.match(/^(\*+) +\[([ xX*])\] +(.+?)\s*$/);
if (task && current) {
const done = task[2] !== ' ';
current.tasks.push({ text: task[3], done, depth: task[1].length - 1 });
current.total += 1;
if (done) current.done += 1;
}
}

const kept = sections.filter((s) => s.total > 0);
const done = kept.reduce((n, s) => n + s.done, 0);
const total = kept.reduce((n, s) => n + s.total, 0);
return {
sections: kept,
done,
total,
percent: total === 0 ? 0 : Math.round((done / total) * 100),
};
}

/** Render a task's text as HTML: escape, then apply `backtick code` and `->` arrows. */
export function renderInline(text: string): string {
return text
.replaceAll('&', '&')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replace(/`([^`]+)`/g, '<code>$1</code>')
.replaceAll('-&gt;', '\u2192');
}

export const progress = parseProgress(progressSrc);
66 changes: 66 additions & 0 deletions site/src/pages/blog/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { getCollection } from 'astro:content';
import Base from '../../layouts/Base.astro';
import { url } from '../../lib/url';
import { progress } from '../../lib/progress';

const posts = (await getCollection('blog')).sort(
(a, b) => b.data.date.valueOf() - a.data.date.valueOf(),
Expand All @@ -15,6 +16,17 @@ const dateFmt = new Intl.DateTimeFormat('en', { dateStyle: 'long' });
<h1 class="page-title">Blog</h1>
<p class="page-lede">Updates and progress on the third edition of <em>Pro Git</em>.</p>

<a class="card progress-card" href={url('/blog/progress/')}>
<div class="progress-head">
<span class="progress-title">Third edition progress</span>
<span class="progress-counts">{progress.done} of {progress.total} tasks · {progress.percent}%</span>
</div>
<div class="progress-bar">
<div class="progress-fill" style={`width: ${progress.percent}%`}></div>
</div>
<span class="progress-cta">See every task →</span>
</a>

<ul class="post-list">
{posts.map((post) => (
<li>
Expand All @@ -30,6 +42,60 @@ const dateFmt = new Intl.DateTimeFormat('en', { dateStyle: 'long' });
</Base>

<style>
.progress-card {
display: block;
margin-bottom: 2rem;
text-decoration: none;
color: var(--text);
}

.progress-card:hover {
border-color: var(--accent);
color: var(--text);
}

.progress-head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 1rem;
margin-bottom: 0.7rem;
}

.progress-title {
font-family: var(--serif);
font-size: 1.2rem;
font-weight: 700;
}

.progress-counts {
font-family: var(--mono);
font-size: 0.82rem;
color: var(--muted);
white-space: nowrap;
}

.progress-bar {
background: var(--bg-inset);
border-radius: 999px;
height: 0.55rem;
overflow: hidden;
}

.progress-fill {
background: var(--accent);
height: 100%;
border-radius: 999px;
}

.progress-cta {
display: inline-block;
margin-top: 0.8rem;
font-size: 0.9rem;
font-weight: 600;
color: var(--accent);
}

.post-list {
list-style: none;
margin: 0;
Expand Down
Loading