summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2022-08-18 14:13:08 -0700
committerJunio C Hamano <gitster@pobox.com>2022-08-18 14:13:08 -0700
commit04495a1941c77d95cb6ad521f45451da4f714af2 (patch)
treead4d9204d5b4c2ac489f99a1051faa1bf48d6ed7
parent472c81a0f3cf8038d39479da1e3840ac33fe6ef8 (diff)
downloadgit-htmldocs-04495a1941c77d95cb6ad521f45451da4f714af2.tar.gz
Autogenerated HTML docs for v2.37.2-382-g795ea
-rw-r--r--RelNotes/2.38.0.txt36
-rw-r--r--cmds-developerinterfaces.txt33
-rw-r--r--cmds-guide.txt24
-rw-r--r--cmds-userinterfaces.txt24
-rw-r--r--git-add.html6
-rw-r--r--git-add.txt4
-rw-r--r--git-am.html11
-rw-r--r--git-am.txt5
-rw-r--r--git-bundle.html16
-rw-r--r--git-bundle.txt13
-rw-r--r--git-cherry-pick.html11
-rw-r--r--git-cherry-pick.txt5
-rw-r--r--git-commit-graph.html8
-rw-r--r--git-commit-graph.txt5
-rw-r--r--git-config.html6
-rw-r--r--git-help.html39
-rw-r--r--git-help.txt27
-rw-r--r--git-merge.html11
-rw-r--r--git-merge.txt5
-rw-r--r--git-multi-pack-index.html6
-rw-r--r--git-multi-pack-index.txt4
-rw-r--r--git-rebase.html11
-rw-r--r--git-rebase.txt5
-rw-r--r--git-rev-list.html5
-rw-r--r--git-revert.html11
-rw-r--r--git-revert.txt5
-rw-r--r--git-upload-pack.html9
-rw-r--r--git-upload-pack.txt7
-rw-r--r--git.html174
-rw-r--r--git.txt17
-rw-r--r--gitformat-bundle.html886
-rw-r--r--gitformat-bundle.txt (renamed from technical/bundle-format.txt)44
-rw-r--r--gitformat-chunk.html895
-rw-r--r--gitformat-chunk.txt (renamed from technical/chunk-format.txt)29
-rw-r--r--gitformat-commit-graph.html1083
-rw-r--r--gitformat-commit-graph.txt (renamed from technical/commit-graph-format.txt)49
-rw-r--r--gitformat-index.html1496
-rw-r--r--gitformat-index.txt (renamed from technical/index-format.txt)22
-rw-r--r--gitformat-pack.html1602
-rw-r--r--gitformat-pack.txt (renamed from technical/pack-format.txt)160
-rw-r--r--gitformat-signature.html1042
-rw-r--r--gitformat-signature.txt (renamed from technical/signature-format.txt)21
-rw-r--r--gitprotocol-capabilities.html1161
-rw-r--r--gitprotocol-capabilities.txt (renamed from technical/protocol-capabilities.txt)28
-rw-r--r--gitprotocol-common.html896
-rw-r--r--gitprotocol-common.txt (renamed from technical/protocol-common.txt)23
-rw-r--r--gitprotocol-http.html1286
-rw-r--r--gitprotocol-http.txt (renamed from technical/http-protocol.txt)35
-rw-r--r--gitprotocol-pack.html1501
-rw-r--r--gitprotocol-pack.txt (renamed from technical/pack-protocol.txt)28
-rw-r--r--gitprotocol-v2.html1504
-rw-r--r--gitprotocol-v2.txt (renamed from technical/protocol-v2.txt)27
-rw-r--r--howto-index.html4
-rw-r--r--howto/coordinate-embargoed-releases.html2
-rw-r--r--howto/keep-canonical-history-correct.html2
-rw-r--r--howto/maintain-git.html2
-rw-r--r--howto/new-command.html2
-rw-r--r--howto/rebase-from-internal-branch.html2
-rw-r--r--howto/rebuild-from-update-hook.html2
-rw-r--r--howto/recover-corrupted-blob-object.html2
-rw-r--r--howto/recover-corrupted-object-harder.html4
-rw-r--r--howto/recover-corrupted-object-harder.txt2
-rw-r--r--howto/revert-a-faulty-merge.html2
-rw-r--r--howto/revert-branch-rebase.html2
-rw-r--r--howto/separating-topic-branches.html2
-rw-r--r--howto/setup-git-server-over-http.html2
-rw-r--r--howto/update-hook-example.html2
-rw-r--r--howto/use-git-daemon.html2
-rw-r--r--howto/using-merge-subtree.html2
-rw-r--r--howto/using-signed-tag-in-pull-request.html2
-rw-r--r--rerere-options.txt9
-rw-r--r--rev-list-options.txt3
-rw-r--r--technical/api-simple-ipc.html4
-rw-r--r--technical/api-simple-ipc.txt2
-rw-r--r--technical/bundle-uri.html1471
-rw-r--r--technical/bundle-uri.txt573
-rw-r--r--technical/cruft-packs.txt123
-rw-r--r--technical/hash-function-transition.html4
-rw-r--r--technical/hash-function-transition.txt2
-rw-r--r--technical/long-running-process-protocol.html4
-rw-r--r--technical/long-running-process-protocol.txt2
-rw-r--r--technical/packfile-uri.txt2
-rw-r--r--technical/partial-clone.html4
-rw-r--r--technical/partial-clone.txt2
-rw-r--r--user-manual.html2
-rw-r--r--user-manual.txt2
86 files changed, 16254 insertions, 356 deletions
diff --git a/RelNotes/2.38.0.txt b/RelNotes/2.38.0.txt
index 38ecfcfe8..4a08602e0 100644
--- a/RelNotes/2.38.0.txt
+++ b/RelNotes/2.38.0.txt
@@ -48,6 +48,12 @@ UI, Workflows & Features
* Operating modes like "--batch" of "git cat-file" command learned to
take NUL-terminated input, instead of one-item-per-line.
+ * "git rm" has become more aware of the sparse-index feature.
+
+ * "git rev-list --disk-usage" learned to take an optional value
+ "human" to show the reported value in human-readable format, like
+ "3.40MiB".
+
Performance, Internal Implementation, Development Support etc.
@@ -107,6 +113,8 @@ Performance, Internal Implementation, Development Support etc.
* "git fetch" client logs the partial clone filter used in the trace2
output.
+ * The "bundle URI" design gets documented.
+
Fixes since v2.37
-----------------
@@ -228,5 +236,33 @@ Fixes since v2.37
* "git symbolic-ref symref non..sen..se" is now diagnosed as an error.
(merge 04ede97211 lt/symbolic-ref-sanity later to maint).
+ * A follow-up fix to a fix for a regression in 2.36.
+ (merge 99ddc24672 ab/hooks-regression-fix later to maint).
+
+ * Avoid repeatedly running getconf to ask libc version in the test
+ suite, and instead just as it once per script.
+ (merge a6a58f7801 pw/use-glibc-tunable-for-malloc-optim later to maint).
+
+ * Platform-specific code that determines if a directory is OK to use
+ as a repository has been taught to report more details, especially
+ on Windows.
+ (merge 3f7207e2ea js/safe-directory-plus later to maint).
+
+ * "vimdiff3" regression fix.
+ (merge 34133d9658 fc/vimdiff-layout-vimdiff3-fix later to maint).
+
+ * "git fsck" reads mode from tree objects but canonicalizes the mode
+ before passing it to the logic to check object sanity, which has
+ hid broken tree objects from the checking logic. This has been
+ corrected, but to help exiting projects with broken tree objects
+ that they cannot fix retroactively, the severity of anomalies this
+ code detects has been demoted to "info" for now.
+ (merge 4dd3b045f5 jk/fsck-tree-mode-bits-fix later to maint).
+
+ * Fixes to sparse index compatibility work for "reset" and "checkout"
+ commands.
+ (merge b15207b8cf vd/sparse-reset-checkout-fixes later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge 94955d576b gc/git-reflog-doc-markup later to maint).
+ (merge efae7ce692 po/doc-add-renormalize later to maint).
diff --git a/cmds-developerinterfaces.txt b/cmds-developerinterfaces.txt
new file mode 100644
index 000000000..e060960bb
--- /dev/null
+++ b/cmds-developerinterfaces.txt
@@ -0,0 +1,33 @@
+linkgit:gitformat-bundle[5]::
+ The bundle file format.
+
+linkgit:gitformat-chunk[5]::
+ Chunk-based file formats.
+
+linkgit:gitformat-commit-graph[5]::
+ Git commit graph format.
+
+linkgit:gitformat-index[5]::
+ Git index format.
+
+linkgit:gitformat-pack[5]::
+ Git pack format.
+
+linkgit:gitformat-signature[5]::
+ Git cryptographic signature formats.
+
+linkgit:gitprotocol-capabilities[5]::
+ Protocol v0 and v1 capabilities.
+
+linkgit:gitprotocol-common[5]::
+ Things common to various protocols.
+
+linkgit:gitprotocol-http[5]::
+ Git HTTP-based protocols.
+
+linkgit:gitprotocol-pack[5]::
+ How packs are transferred over-the-wire.
+
+linkgit:gitprotocol-v2[5]::
+ Git Wire Protocol, Version 2.
+
diff --git a/cmds-guide.txt b/cmds-guide.txt
index cbf61cdca..3c0eeb3dc 100644
--- a/cmds-guide.txt
+++ b/cmds-guide.txt
@@ -1,9 +1,3 @@
-linkgit:gitattributes[5]::
- Defining attributes per path.
-
-linkgit:gitcli[7]::
- Git command-line interface and conventions.
-
linkgit:gitcore-tutorial[7]::
A Git core tutorial for developers.
@@ -25,30 +19,12 @@ linkgit:gitfaq[7]::
linkgit:gitglossary[7]::
A Git Glossary.
-linkgit:githooks[5]::
- Hooks used by Git.
-
-linkgit:gitignore[5]::
- Specifies intentionally untracked files to ignore.
-
-linkgit:gitmailmap[5]::
- Map author/committer names and/or E-Mail addresses.
-
-linkgit:gitmodules[5]::
- Defining submodule properties.
-
linkgit:gitnamespaces[7]::
Git namespaces.
linkgit:gitremote-helpers[7]::
Helper programs to interact with remote repositories.
-linkgit:gitrepository-layout[5]::
- Git Repository Layout.
-
-linkgit:gitrevisions[7]::
- Specifying revisions and ranges for Git.
-
linkgit:gitsubmodules[7]::
Mounting one repository inside another.
diff --git a/cmds-userinterfaces.txt b/cmds-userinterfaces.txt
new file mode 100644
index 000000000..dae805335
--- /dev/null
+++ b/cmds-userinterfaces.txt
@@ -0,0 +1,24 @@
+linkgit:gitattributes[5]::
+ Defining attributes per path.
+
+linkgit:gitcli[7]::
+ Git command-line interface and conventions.
+
+linkgit:githooks[5]::
+ Hooks used by Git.
+
+linkgit:gitignore[5]::
+ Specifies intentionally untracked files to ignore.
+
+linkgit:gitmailmap[5]::
+ Map author/committer names and/or E-Mail addresses.
+
+linkgit:gitmodules[5]::
+ Defining submodule properties.
+
+linkgit:gitrepository-layout[5]::
+ Git Repository Layout.
+
+linkgit:gitrevisions[7]::
+ Specifying revisions and ranges for Git.
+
diff --git a/git-add.html b/git-add.html
index 1e163d37d..33c9770e9 100644
--- a/git-add.html
+++ b/git-add.html
@@ -1030,7 +1030,9 @@ for "git add --no-all &lt;pathspec&gt;&#8230;", i.e. ignored removed files.</p><
forcibly add them again to the index. This is useful after
changing <code>core.autocrlf</code> configuration or the <code>text</code> attribute
in order to correct files added with wrong CRLF/LF line endings.
- This option implies <code>-u</code>.
+ This option implies <code>-u</code>. Lone CR characters are untouched, thus
+ while a CRLF cleans to LF, a CRCRLF sequence is only partially
+ cleaned to CRLF.
</p>
</dd>
<dt class="hdlist1">
@@ -1387,7 +1389,7 @@ modifying the contents of context or removal lines
<div id="footer">
<div id="footer-text">
Last updated
- 2021-10-14 10:10:01 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-add.txt b/git-add.txt
index 11eb70f16..9b37f3565 100644
--- a/git-add.txt
+++ b/git-add.txt
@@ -188,7 +188,9 @@ for "git add --no-all <pathspec>...", i.e. ignored removed files.
forcibly add them again to the index. This is useful after
changing `core.autocrlf` configuration or the `text` attribute
in order to correct files added with wrong CRLF/LF line endings.
- This option implies `-u`.
+ This option implies `-u`. Lone CR characters are untouched, thus
+ while a CRLF cleans to LF, a CRCRLF sequence is only partially
+ cleaned to CRLF.
--chmod=(+|-)x::
Override the executable bit of the added files. The executable
diff --git a/git-am.html b/git-am.html
index 8f339034d..80551be05 100644
--- a/git-am.html
+++ b/git-am.html
@@ -957,8 +957,13 @@ default. You can use <code>--no-utf8</code> to override this.</p></div>
</dt>
<dd>
<p>
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+ After the rerere mechanism reuses a recorded resolution on
+ the current conflict to update the files in the working
+ tree, allow it to also update the index with the result of
+ resolution. <code>--no-rerere-autoupdate</code> is a good way to
+ double-check what <code>rerere</code> did and catch potential
+ mismerges, before committing the result to the index with a
+ separate <code>git add</code>.
</p>
</dd>
<dt class="hdlist1">
@@ -1233,7 +1238,7 @@ information.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-01-05 14:13:29 PST
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-am.txt b/git-am.txt
index 09107fb10..320da6c4f 100644
--- a/git-am.txt
+++ b/git-am.txt
@@ -112,10 +112,7 @@ default. You can use `--no-utf8` to override this.
am.threeWay configuration variable. For more information,
see am.threeWay in linkgit:git-config[1].
---rerere-autoupdate::
---no-rerere-autoupdate::
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
--ignore-space-change::
--ignore-whitespace::
diff --git a/git-bundle.html b/git-bundle.html
index a8e64dc33..ef7ac8bfc 100644
--- a/git-bundle.html
+++ b/git-bundle.html
@@ -793,10 +793,8 @@ exclusions, and users should not be concerned about the difference. By
using "thin packs", bundles created using exclusions are smaller in
size. That they&#8217;re "thin" under the hood is merely noted here as a
curiosity, and as a reference to other documentation.</p></div>
-<div class="paragraph"><p>See <a href="technical/bundle-format.html">the <code>bundle-format</code>
-documentation</a> for more details and the discussion of "thin pack" in
-<a href="technical/pack-format.html">the pack format documentation</a> for
-further details.</p></div>
+<div class="paragraph"><p>See <a href="gitformat-bundle.html">gitformat-bundle(5)</a> for more details and the discussion of
+"thin pack" in <a href="gitformat-pack.html">gitformat-pack(5)</a> for further details.</p></div>
</div>
</div>
<div class="sect1">
@@ -825,7 +823,7 @@ verify &lt;file&gt;
commits exist and are fully linked in the current repository.
Then, <em>git bundle</em> prints a list of missing commits, if any.
Finally, information about additional capabilities, such as "object
- filter", is printed. See "Capabilities" in link:technical/bundle-format.html
+ filter", is printed. See "Capabilities" in <a href="gitformat-bundle.html">gitformat-bundle(5)</a>
for more information. The exit code is zero for success, but will
be nonzero if the bundle file is invalid.
</p>
@@ -1114,6 +1112,12 @@ references when fetching:</p></div>
</div>
</div>
<div class="sect1">
+<h2 id="_file_format">FILE FORMAT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>See <a href="gitformat-bundle.html">gitformat-bundle(5)</a>.</p></div>
+</div>
+</div>
+<div class="sect1">
<h2 id="_git">GIT</h2>
<div class="sectionbody">
<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
@@ -1124,7 +1128,7 @@ references when fetching:</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-04-04 11:19:32 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-bundle.txt b/git-bundle.txt
index 7685b5704..6da617224 100644
--- a/git-bundle.txt
+++ b/git-bundle.txt
@@ -56,10 +56,8 @@ using "thin packs", bundles created using exclusions are smaller in
size. That they're "thin" under the hood is merely noted here as a
curiosity, and as a reference to other documentation.
-See link:technical/bundle-format.html[the `bundle-format`
-documentation] for more details and the discussion of "thin pack" in
-link:technical/pack-format.html[the pack format documentation] for
-further details.
+See linkgit:gitformat-bundle[5] for more details and the discussion of
+"thin pack" in linkgit:gitformat-pack[5] for further details.
OPTIONS
-------
@@ -77,7 +75,7 @@ verify <file>::
commits exist and are fully linked in the current repository.
Then, 'git bundle' prints a list of missing commits, if any.
Finally, information about additional capabilities, such as "object
- filter", is printed. See "Capabilities" in link:technical/bundle-format.html
+ filter", is printed. See "Capabilities" in linkgit:gitformat-bundle[5]
for more information. The exit code is zero for success, but will
be nonzero if the bundle file is invalid.
@@ -337,6 +335,11 @@ You can also see what references it offers:
$ git ls-remote mybundle
----------------
+FILE FORMAT
+-----------
+
+See linkgit:gitformat-bundle[5].
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/git-cherry-pick.html b/git-cherry-pick.html
index 15451e184..2fbd7af8a 100644
--- a/git-cherry-pick.html
+++ b/git-cherry-pick.html
@@ -1018,8 +1018,13 @@ effect to your index in a row.</p></div>
</dt>
<dd>
<p>
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+ After the rerere mechanism reuses a recorded resolution on
+ the current conflict to update the files in the working
+ tree, allow it to also update the index with the result of
+ resolution. <code>--no-rerere-autoupdate</code> is a good way to
+ double-check what <code>rerere</code> did and catch potential
+ mismerges, before committing the result to the index with a
+ separate <code>git add</code>.
</p>
</dd>
</dl></div>
@@ -1212,7 +1217,7 @@ try to apply the change introduced by <code>topic^</code> again,
<div id="footer">
<div id="footer-text">
Last updated
- 2021-12-10 14:52:02 PST
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-cherry-pick.txt b/git-cherry-pick.txt
index 78dcc9171..1e8ac9df6 100644
--- a/git-cherry-pick.txt
+++ b/git-cherry-pick.txt
@@ -156,10 +156,7 @@ effect to your index in a row.
Pass the merge strategy-specific option through to the
merge strategy. See linkgit:git-merge[1] for details.
---rerere-autoupdate::
---no-rerere-autoupdate::
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
SEQUENCER SUBCOMMANDS
---------------------
diff --git a/git-commit-graph.html b/git-commit-graph.html
index d1b20d938..6d6c4192c 100644
--- a/git-commit-graph.html
+++ b/git-commit-graph.html
@@ -930,6 +930,12 @@ Write a commit-graph file containing all commits in the current
</div>
</div>
<div class="sect1">
+<h2 id="_file_format">FILE FORMAT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>see <a href="gitformat-commit-graph.html">gitformat-commit-graph(5)</a>.</p></div>
+</div>
+</div>
+<div class="sect1">
<h2 id="_git">GIT</h2>
<div class="sectionbody">
<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
@@ -940,7 +946,7 @@ Write a commit-graph file containing all commits in the current
<div id="footer">
<div id="footer-text">
Last updated
- 2020-11-02 18:01:42 PST
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-commit-graph.txt b/git-commit-graph.txt
index e1f48c95b..047decdb6 100644
--- a/git-commit-graph.txt
+++ b/git-commit-graph.txt
@@ -143,6 +143,11 @@ $ git rev-parse HEAD | git commit-graph write --stdin-commits --append
------------------------------------------------
+FILE FORMAT
+-----------
+
+see linkgit:gitformat-commit-graph[5].
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/git-config.html b/git-config.html
index 4d03f2ce9..ffff83d69 100644
--- a/git-config.html
+++ b/git-config.html
@@ -7681,7 +7681,7 @@ lsrefs.unborn
<p>
May be "advertise" (the default), "allow", or "ignore". If "advertise",
the server will respond to the client sending "unborn" (as described in
- protocol-v2.txt) and will advertise support for this feature during the
+ <a href="gitprotocol-v2.html">gitprotocol-v2(5)</a>) and will advertise support for this feature during the
protocol v2 capability advertisement. "allow" is the same as
"advertise" except that the server will not advertise support for this
feature; this is useful for load-balanced servers that cannot be
@@ -8845,7 +8845,7 @@ pack.writeReverseIndex
<dd>
<p>
When true, git will write a corresponding .rev file (see:
- <a href="../technical/pack-format.html">Documentation/technical/pack-format.txt</a>)
+ <a href="gitformat-pack.html">gitformat-pack(5)</a>)
for each new packfile that it writes in all places except for
<a href="git-fast-import.html">git-fast-import(1)</a> and in the bulk checkin mechanism.
Defaults to false.
@@ -8990,7 +8990,7 @@ protocol.version
</li>
<li>
<p>
-<code>2</code> - <a href="technical/protocol-v2.html">wire protocol version 2</a>.
+<code>2</code> - Wire protocol version 2, see <a href="gitprotocol-v2.html">gitprotocol-v2(5)</a>.
</p>
</li>
</ul></div>
diff --git a/git-help.html b/git-help.html
index ac98efd3b..12a904cf6 100644
--- a/git-help.html
+++ b/git-help.html
@@ -750,9 +750,11 @@ git-help(1) Manual Page
<div class="sectionbody">
<div class="verseblock">
<pre class="content"><em>git help</em> [-a|--all] [--[no-]verbose] [--[no-]external-commands] [--[no-]aliases]
-<em>git help</em> [[-i|--info] [-m|--man] [-w|--web]] [&lt;command&gt;|&lt;guide&gt;]
+<em>git help</em> [[-i|--info] [-m|--man] [-w|--web]] [&lt;command&gt;|&lt;doc&gt;]
<em>git help</em> [-g|--guides]
-<em>git help</em> [-c|--config]</pre>
+<em>git help</em> [-c|--config]
+<em>git help</em> [--user-interfaces]
+<em>git help</em> [--developer-interfaces]</pre>
<div class="attribution">
</div></div>
</div>
@@ -760,15 +762,15 @@ git-help(1) Manual Page
<div class="sect1">
<h2 id="_description">DESCRIPTION</h2>
<div class="sectionbody">
-<div class="paragraph"><p>With no options and no <em>&lt;command&gt;</em> or <em>&lt;guide&gt;</em> given, the synopsis of the <em>git</em>
+<div class="paragraph"><p>With no options and no <em>&lt;command&gt;</em> or <em>&lt;doc&gt;</em> given, the synopsis of the <em>git</em>
command and a list of the most commonly used Git commands are printed
on the standard output.</p></div>
<div class="paragraph"><p>If the option <code>--all</code> or <code>-a</code> is given, all available commands are
printed on the standard output.</p></div>
<div class="paragraph"><p>If the option <code>--guides</code> or <code>-g</code> is given, a list of the
Git concept guides is also printed on the standard output.</p></div>
-<div class="paragraph"><p>If a command, or a guide, is given, a manual page for that command or
-guide is brought up. The <em>man</em> program is used by default for this
+<div class="paragraph"><p>If a command or other documentation is given, the relevant manual page
+will be brought up. The <em>man</em> program is used by default for this
purpose, but this can be overridden by other options or configuration
variables.</p></div>
<div class="paragraph"><p>If an alias is given, git shows the definition of the alias on
@@ -846,6 +848,31 @@ former is internally converted into the latter.</p></div>
</p>
</dd>
<dt class="hdlist1">
+--user-interfaces
+</dt>
+<dd>
+<p>
+ Prints a list of the repository, command and file interfaces
+ documentation on the standard output.
+</p>
+<div class="paragraph"><p>In-repository file interfaces such as <code>.git/info/exclude</code> are
+documented here (see <a href="gitrepository-layout.html">gitrepository-layout(5)</a>), as well as
+in-tree configuration such as <code>.mailmap</code> (see <a href="gitmailmap.html">gitmailmap(5)</a>).</p></div>
+<div class="paragraph"><p>This section of the documentation also covers general or widespread
+user-interface conventions (e.g. <a href="gitcli.html">gitcli(7)</a>), and
+pseudo-configuration such as the file-based <code>.git/hooks/*</code> interface
+described in <a href="githooks.html">githooks(5)</a>.</p></div>
+</dd>
+<dt class="hdlist1">
+--developer-interfaces
+</dt>
+<dd>
+<p>
+ Print list of file formats, protocols and other developer
+ interfaces documentation on the standard output.
+</p>
+</dd>
+<dt class="hdlist1">
-i
</dt>
<dt class="hdlist1">
@@ -1029,7 +1056,7 @@ See <a href="git-config.html">git-config(1)</a> for more information about this.
<div id="footer">
<div id="footer-text">
Last updated
- 2022-03-09 14:17:38 PST
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-help.txt b/git-help.txt
index 239c68db4..2b0b5e390 100644
--- a/git-help.txt
+++ b/git-help.txt
@@ -9,14 +9,16 @@ SYNOPSIS
--------
[verse]
'git help' [-a|--all] [--[no-]verbose] [--[no-]external-commands] [--[no-]aliases]
-'git help' [[-i|--info] [-m|--man] [-w|--web]] [<command>|<guide>]
+'git help' [[-i|--info] [-m|--man] [-w|--web]] [<command>|<doc>]
'git help' [-g|--guides]
'git help' [-c|--config]
+'git help' [--user-interfaces]
+'git help' [--developer-interfaces]
DESCRIPTION
-----------
-With no options and no '<command>' or '<guide>' given, the synopsis of the 'git'
+With no options and no '<command>' or '<doc>' given, the synopsis of the 'git'
command and a list of the most commonly used Git commands are printed
on the standard output.
@@ -26,8 +28,8 @@ printed on the standard output.
If the option `--guides` or `-g` is given, a list of the
Git concept guides is also printed on the standard output.
-If a command, or a guide, is given, a manual page for that command or
-guide is brought up. The 'man' program is used by default for this
+If a command or other documentation is given, the relevant manual page
+will be brought up. The 'man' program is used by default for this
purpose, but this can be overridden by other options or configuration
variables.
@@ -69,6 +71,23 @@ OPTIONS
--guides::
Prints a list of the Git concept guides on the standard output.
+--user-interfaces::
+ Prints a list of the repository, command and file interfaces
+ documentation on the standard output.
++
+In-repository file interfaces such as `.git/info/exclude` are
+documented here (see linkgit:gitrepository-layout[5]), as well as
+in-tree configuration such as `.mailmap` (see linkgit:gitmailmap[5]).
++
+This section of the documentation also covers general or widespread
+user-interface conventions (e.g. linkgit:gitcli[7]), and
+pseudo-configuration such as the file-based `.git/hooks/*` interface
+described in linkgit:githooks[5].
+
+--developer-interfaces::
+ Print list of file formats, protocols and other developer
+ interfaces documentation on the standard output.
+
-i::
--info::
Display manual page for the command in the 'info' format. The
diff --git a/git-merge.html b/git-merge.html
index aff0c4819..70dd8fdb4 100644
--- a/git-merge.html
+++ b/git-merge.html
@@ -1154,8 +1154,13 @@ will be appended to the specified message.</p></div>
</dt>
<dd>
<p>
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+ After the rerere mechanism reuses a recorded resolution on
+ the current conflict to update the files in the working
+ tree, allow it to also update the index with the result of
+ resolution. <code>--no-rerere-autoupdate</code> is a good way to
+ double-check what <code>rerere</code> did and catch potential
+ mismerges, before committing the result to the index with a
+ separate <code>git add</code>.
</p>
</dd>
<dt class="hdlist1">
@@ -2316,7 +2321,7 @@ branch.&lt;name&gt;.mergeOptions
<div id="footer">
<div id="footer-text">
Last updated
- 2022-01-05 14:13:29 PST
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-merge.txt b/git-merge.txt
index 3125473cc..fee1dc2df 100644
--- a/git-merge.txt
+++ b/git-merge.txt
@@ -90,10 +90,7 @@ invocations. The automated message can include the branch description.
If `--log` is specified, a shortlog of the commits being merged
will be appended to the specified message.
---rerere-autoupdate::
---no-rerere-autoupdate::
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
--overwrite-ignore::
--no-overwrite-ignore::
diff --git a/git-multi-pack-index.html b/git-multi-pack-index.html
index eda4be687..04fcbab0e 100644
--- a/git-multi-pack-index.html
+++ b/git-multi-pack-index.html
@@ -942,8 +942,8 @@ Verify the MIDX file for the packfiles in the current <code>.git</code> director
<h2 id="_see_also">SEE ALSO</h2>
<div class="sectionbody">
<div class="paragraph"><p>See <a href="technical/multi-pack-index.html">The Multi-Pack-Index Design
-Document</a> and <a href="technical/pack-format.html">The Multi-Pack-Index
-Format</a> for more information on the multi-pack-index feature.</p></div>
+Document</a> and <a href="gitformat-pack.html">gitformat-pack(5)</a> for more information on the
+multi-pack-index feature and its file format.</p></div>
</div>
</div>
<div class="sect1">
@@ -957,7 +957,7 @@ Format</a> for more information on the multi-pack-index feature.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2021-10-29 16:18:45 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-multi-pack-index.txt b/git-multi-pack-index.txt
index c588fb91a..a48c3d5ea 100644
--- a/git-multi-pack-index.txt
+++ b/git-multi-pack-index.txt
@@ -128,8 +128,8 @@ $ git multi-pack-index verify
SEE ALSO
--------
See link:technical/multi-pack-index.html[The Multi-Pack-Index Design
-Document] and link:technical/pack-format.html[The Multi-Pack-Index
-Format] for more information on the multi-pack-index feature.
+Document] and linkgit:gitformat-pack[5] for more information on the
+multi-pack-index feature and its file format.
GIT
diff --git a/git-rebase.html b/git-rebase.html
index f9a7494be..b653e5862 100644
--- a/git-rebase.html
+++ b/git-rebase.html
@@ -1194,8 +1194,13 @@ which makes little sense.</p></div>
</dt>
<dd>
<p>
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+ After the rerere mechanism reuses a recorded resolution on
+ the current conflict to update the files in the working
+ tree, allow it to also update the index with the result of
+ resolution. <code>--no-rerere-autoupdate</code> is a good way to
+ double-check what <code>rerere</code> did and catch potential
+ mismerges, before committing the result to the index with a
+ separate <code>git add</code>.
</p>
</dd>
<dt class="hdlist1">
@@ -2749,7 +2754,7 @@ sequence.editor
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-01 10:59:02 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-rebase.txt b/git-rebase.txt
index 080658c87..187794218 100644
--- a/git-rebase.txt
+++ b/git-rebase.txt
@@ -376,10 +376,7 @@ See also INCOMPATIBLE OPTIONS below.
+
See also INCOMPATIBLE OPTIONS below.
---rerere-autoupdate::
---no-rerere-autoupdate::
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
-S[<keyid>]::
--gpg-sign[=<keyid>]::
diff --git a/git-rev-list.html b/git-rev-list.html
index db33ed29f..eebfdf3fd 100644
--- a/git-rev-list.html
+++ b/git-rev-list.html
@@ -1219,6 +1219,9 @@ explicitly.</p></div>
<dt class="hdlist1">
--disk-usage
</dt>
+<dt class="hdlist1">
+--disk-usage=human
+</dt>
<dd>
<p>
Suppress normal output; instead, print the sum of the bytes used
@@ -1228,6 +1231,8 @@ explicitly.</p></div>
faster (especially with <code>--use-bitmap-index</code>). See the <code>CAVEATS</code>
section in <a href="git-cat-file.html">git-cat-file(1)</a> for the limitations of what
"on-disk storage" means.
+ With the optional value <code>human</code>, on-disk storage size is shown
+ in human-readable string(e.g. 12.24 Kib, 3.50 Mib).
</p>
</dd>
<dt class="hdlist1">
diff --git a/git-revert.html b/git-revert.html
index 5dff63692..caa722d1e 100644
--- a/git-revert.html
+++ b/git-revert.html
@@ -926,8 +926,13 @@ effect to your index in a row.</p></div>
</dt>
<dd>
<p>
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+ After the rerere mechanism reuses a recorded resolution on
+ the current conflict to update the files in the working
+ tree, allow it to also update the index with the result of
+ resolution. <code>--no-rerere-autoupdate</code> is a good way to
+ double-check what <code>rerere</code> did and catch potential
+ mismerges, before committing the result to the index with a
+ separate <code>git add</code>.
</p>
</dd>
<dt class="hdlist1">
@@ -1035,7 +1040,7 @@ effect to your index in a row.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-06-17 10:57:33 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-revert.txt b/git-revert.txt
index 8463fe9cf..0105a54c1 100644
--- a/git-revert.txt
+++ b/git-revert.txt
@@ -112,10 +112,7 @@ effect to your index in a row.
Pass the merge strategy-specific option through to the
merge strategy. See linkgit:git-merge[1] for details.
---rerere-autoupdate::
---no-rerere-autoupdate::
- Allow the rerere mechanism to update the index with the
- result of auto-conflict resolution if possible.
+include::rerere-options.txt[]
--reference::
Instead of starting the body of the log message with "This
diff --git a/git-upload-pack.html b/git-upload-pack.html
index 5041baf7e..2cfd795d9 100644
--- a/git-upload-pack.html
+++ b/git-upload-pack.html
@@ -803,10 +803,9 @@ repository. For push operations, see <em>git send-pack</em>.</p></div>
<p>
Used by <a href="git-http-backend.html">git-http-backend(1)</a> to serve up
<code>$GIT_URL/info/refs?service=git-upload-pack</code> requests. See
- "Smart Clients" in <a href="technical/http-protocol.html">the HTTP
- transfer protocols</a> documentation and "HTTP Transport" in
- <a href="technical/protocol-v2.html">the Git Wire Protocol, Version
- 2</a> documentation. Also understood by
+ "Smart Clients" in <a href="gitprotocol-http.html">gitprotocol-http(5)</a> and "HTTP
+ Transport" in in the <a href="gitprotocol-v2.html">gitprotocol-v2(5)</a>
+ documentation. Also understood by
<a href="git-receive-pack.html">git-receive-pack(1)</a>.
</p>
</dd>
@@ -855,7 +854,7 @@ repository. For push operations, see <em>git send-pack</em>.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2021-09-23 14:33:59 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git-upload-pack.txt b/git-upload-pack.txt
index 8f87b23ea..3f89d6407 100644
--- a/git-upload-pack.txt
+++ b/git-upload-pack.txt
@@ -39,10 +39,9 @@ OPTIONS
--http-backend-info-refs::
Used by linkgit:git-http-backend[1] to serve up
`$GIT_URL/info/refs?service=git-upload-pack` requests. See
- "Smart Clients" in link:technical/http-protocol.html[the HTTP
- transfer protocols] documentation and "HTTP Transport" in
- link:technical/protocol-v2.html[the Git Wire Protocol, Version
- 2] documentation. Also understood by
+ "Smart Clients" in linkgit:gitprotocol-http[5] and "HTTP
+ Transport" in in the linkgit:gitprotocol-v2[5]
+ documentation. Also understood by
linkgit:git-receive-pack[1].
<directory>::
diff --git a/git.html b/git.html
index d8a03143a..7c83e67a0 100644
--- a/git.html
+++ b/git.html
@@ -2385,22 +2385,6 @@ users typically do not use them directly.</p></div>
<div class="paragraph"><p>The following documentation pages are guides about Git concepts.</p></div>
<div class="dlist"><dl>
<dt class="hdlist1">
-<a href="gitattributes.html">gitattributes(5)</a>
-</dt>
-<dd>
-<p>
- Defining attributes per path.
-</p>
-</dd>
-<dt class="hdlist1">
-<a href="gitcli.html">gitcli(7)</a>
-</dt>
-<dd>
-<p>
- Git command-line interface and conventions.
-</p>
-</dd>
-<dt class="hdlist1">
<a href="gitcore-tutorial.html">gitcore-tutorial(7)</a>
</dt>
<dd>
@@ -2457,6 +2441,80 @@ users typically do not use them directly.</p></div>
</p>
</dd>
<dt class="hdlist1">
+<a href="gitnamespaces.html">gitnamespaces(7)</a>
+</dt>
+<dd>
+<p>
+ Git namespaces.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitremote-helpers.html">gitremote-helpers(7)</a>
+</dt>
+<dd>
+<p>
+ Helper programs to interact with remote repositories.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitsubmodules.html">gitsubmodules(7)</a>
+</dt>
+<dd>
+<p>
+ Mounting one repository inside another.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gittutorial.html">gittutorial(7)</a>
+</dt>
+<dd>
+<p>
+ A tutorial introduction to Git.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gittutorial-2.html">gittutorial-2(7)</a>
+</dt>
+<dd>
+<p>
+ A tutorial introduction to Git: part two.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitworkflows.html">gitworkflows(7)</a>
+</dt>
+<dd>
+<p>
+ An overview of recommended workflows with Git.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_repository_command_and_file_interfaces">Repository, command and file interfaces</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This documentation discusses repository and command interfaces which
+users are expected to interact with directly. See <code>--user-formats</code> in
+<a href="git-help.html">git-help(1)</a> for more details on the critera.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<a href="gitattributes.html">gitattributes(5)</a>
+</dt>
+<dd>
+<p>
+ Defining attributes per path.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitcli.html">gitcli(7)</a>
+</dt>
+<dd>
+<p>
+ Git command-line interface and conventions.
+</p>
+</dd>
+<dt class="hdlist1">
<a href="githooks.html">githooks(5)</a>
</dt>
<dd>
@@ -2489,67 +2547,117 @@ users typically do not use them directly.</p></div>
</p>
</dd>
<dt class="hdlist1">
-<a href="gitnamespaces.html">gitnamespaces(7)</a>
+<a href="gitrepository-layout.html">gitrepository-layout(5)</a>
</dt>
<dd>
<p>
- Git namespaces.
+ Git Repository Layout.
</p>
</dd>
<dt class="hdlist1">
-<a href="gitremote-helpers.html">gitremote-helpers(7)</a>
+<a href="gitrevisions.html">gitrevisions(7)</a>
</dt>
<dd>
<p>
- Helper programs to interact with remote repositories.
+ Specifying revisions and ranges for Git.
</p>
</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_file_formats_protocols_and_other_developer_interfaces">File formats, protocols and other developer interfaces</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This documentation discusses file formats, over-the-wire protocols and
+other git developer interfaces. See <code>--developer-interfaces</code> in
+<a href="git-help.html">git-help(1)</a>.</p></div>
+<div class="dlist"><dl>
<dt class="hdlist1">
-<a href="gitrepository-layout.html">gitrepository-layout(5)</a>
+<a href="gitformat-bundle.html">gitformat-bundle(5)</a>
</dt>
<dd>
<p>
- Git Repository Layout.
+ The bundle file format.
</p>
</dd>
<dt class="hdlist1">
-<a href="gitrevisions.html">gitrevisions(7)</a>
+<a href="gitformat-chunk.html">gitformat-chunk(5)</a>
</dt>
<dd>
<p>
- Specifying revisions and ranges for Git.
+ Chunk-based file formats.
</p>
</dd>
<dt class="hdlist1">
-<a href="gitsubmodules.html">gitsubmodules(7)</a>
+<a href="gitformat-commit-graph.html">gitformat-commit-graph(5)</a>
</dt>
<dd>
<p>
- Mounting one repository inside another.
+ Git commit graph format.
</p>
</dd>
<dt class="hdlist1">
-<a href="gittutorial.html">gittutorial(7)</a>
+<a href="gitformat-index.html">gitformat-index(5)</a>
</dt>
<dd>
<p>
- A tutorial introduction to Git.
+ Git index format.
</p>
</dd>
<dt class="hdlist1">
-<a href="gittutorial-2.html">gittutorial-2(7)</a>
+<a href="gitformat-pack.html">gitformat-pack(5)</a>
</dt>
<dd>
<p>
- A tutorial introduction to Git: part two.
+ Git pack format.
</p>
</dd>
<dt class="hdlist1">
-<a href="gitworkflows.html">gitworkflows(7)</a>
+<a href="gitformat-signature.html">gitformat-signature(5)</a>
</dt>
<dd>
<p>
- An overview of recommended workflows with Git.
+ Git cryptographic signature formats.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitprotocol-capabilities.html">gitprotocol-capabilities(5)</a>
+</dt>
+<dd>
+<p>
+ Protocol v0 and v1 capabilities.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitprotocol-common.html">gitprotocol-common(5)</a>
+</dt>
+<dd>
+<p>
+ Things common to various protocols.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitprotocol-http.html">gitprotocol-http(5)</a>
+</dt>
+<dd>
+<p>
+ Git HTTP-based protocols.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitprotocol-pack.html">gitprotocol-pack(5)</a>
+</dt>
+<dd>
+<p>
+ How packs are transferred over-the-wire.
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="gitprotocol-v2.html">gitprotocol-v2(5)</a>
+</dt>
+<dd>
+<p>
+ Git Wire Protocol, Version 2.
</p>
</dd>
</dl></div>
@@ -3660,7 +3768,7 @@ the Git Security mailing list &lt;<a href="mailto:git-security@googlegroups.com"
<div id="footer">
<div id="footer-text">
Last updated
- 2022-07-27 09:46:08 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/git.txt b/git.txt
index 47a6095ff..0ef7f5e4e 100644
--- a/git.txt
+++ b/git.txt
@@ -339,6 +339,23 @@ The following documentation pages are guides about Git concepts.
include::cmds-guide.txt[]
+Repository, command and file interfaces
+---------------------------------------
+
+This documentation discusses repository and command interfaces which
+users are expected to interact with directly. See `--user-formats` in
+linkgit:git-help[1] for more details on the critera.
+
+include::cmds-userinterfaces.txt[]
+
+File formats, protocols and other developer interfaces
+------------------------------------------------------
+
+This documentation discusses file formats, over-the-wire protocols and
+other git developer interfaces. See `--developer-interfaces` in
+linkgit:git-help[1].
+
+include::cmds-developerinterfaces.txt[]
Configuration Mechanism
-----------------------
diff --git a/gitformat-bundle.html b/gitformat-bundle.html
new file mode 100644
index 000000000..59269de6f
--- /dev/null
+++ b/gitformat-bundle.html
@@ -0,0 +1,886 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitformat-bundle(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitformat-bundle(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitformat-bundle -
+ The bundle file format
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">*.bundle
+*.bdl</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Git bundle format is a format that represents both refs and Git
+objects. A bundle is a header in a format similar to
+<a href="git-show-ref.html">git-show-ref(1)</a> followed by a pack in *.pack format.</p></div>
+<div class="paragraph"><p>The format is created and read by the <a href="git-bundle.html">git-bundle(1)</a> command,
+and supported by e.g. <a href="git-fetch.html">git-fetch(1)</a> and <a href="git-clone.html">git-clone(1)</a>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_format">FORMAT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>We will use ABNF notation to define the Git bundle format. See
+<a href="gitprotocol-common.html">gitprotocol-common(5)</a> for the details.</p></div>
+<div class="paragraph"><p>A v2 bundle looks like this:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>bundle = signature *prerequisite *reference LF pack
+signature = "# v2 git bundle" LF
+
+prerequisite = "-" obj-id SP comment LF
+comment = *CHAR
+reference = obj-id SP refname LF
+
+pack = ... ; packfile</code></pre>
+</div></div>
+<div class="paragraph"><p>A v3 bundle looks like this:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>bundle = signature *capability *prerequisite *reference LF pack
+signature = "# v3 git bundle" LF
+
+capability = "@" key ["=" value] LF
+prerequisite = "-" obj-id SP comment LF
+comment = *CHAR
+reference = obj-id SP refname LF
+key = 1*(ALPHA / DIGIT / "-")
+value = *(%01-09 / %0b-FF)
+
+pack = ... ; packfile</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_semantics">SEMANTICS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>A Git bundle consists of several parts.</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+"Capabilities", which are only in the v3 format, indicate functionality that
+ the bundle requires to be read properly.
+</p>
+</li>
+<li>
+<p>
+"Prerequisites" lists the objects that are NOT included in the bundle and the
+ reader of the bundle MUST already have, in order to use the data in the
+ bundle. The objects stored in the bundle may refer to prerequisite objects and
+ anything reachable from them (e.g. a tree object in the bundle can reference
+ a blob that is reachable from a prerequisite) and/or expressed as a delta
+ against prerequisite objects.
+</p>
+</li>
+<li>
+<p>
+"References" record the tips of the history graph, iow, what the reader of the
+ bundle CAN "git fetch" from it.
+</p>
+</li>
+<li>
+<p>
+"Pack" is the pack data stream "git fetch" would send, if you fetch from a
+ repository that has the references recorded in the "References" above into a
+ repository that has references pointing at the objects listed in
+ "Prerequisites" above.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>In the bundle format, there can be a comment following a prerequisite obj-id.
+This is a comment and it has no specific meaning. The writer of the bundle MAY
+put any string here. The reader of the bundle MUST ignore the comment.</p></div>
+<div class="sect2">
+<h3 id="_note_on_the_shallow_clone_and_a_git_bundle">Note on the shallow clone and a Git bundle</h3>
+<div class="paragraph"><p>Note that the prerequisites does not represent a shallow-clone boundary. The
+semantics of the prerequisites and the shallow-clone boundaries are different,
+and the Git bundle v2 format cannot represent a shallow clone repository.</p></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_capabilities">CAPABILITIES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Because there is no opportunity for negotiation, unknown capabilities cause <em>git
+bundle</em> to abort.</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+<code>object-format</code> specifies the hash algorithm in use, and can take the same
+ values as the <code>extensions.objectFormat</code> configuration value.
+</p>
+</li>
+<li>
+<p>
+<code>filter</code> specifies an object filter as in the <code>--filter</code> option in
+ <a href="git-rev-list.html">git-rev-list(1)</a>. The resulting pack-file must be marked as a
+ <code>.promisor</code> pack-file after it is unbundled.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/bundle-format.txt b/gitformat-bundle.txt
index b9be8644c..00e0a20e6 100644
--- a/technical/bundle-format.txt
+++ b/gitformat-bundle.txt
@@ -1,11 +1,33 @@
-= Git bundle v2 format
+gitformat-bundle(5)
+===================
-The Git bundle format is a format that represents both refs and Git objects.
+NAME
+----
+gitformat-bundle - The bundle file format
+
+
+SYNOPSIS
+--------
+[verse]
+*.bundle
+*.bdl
+
+DESCRIPTION
+-----------
+
+The Git bundle format is a format that represents both refs and Git
+objects. A bundle is a header in a format similar to
+linkgit:git-show-ref[1] followed by a pack in *.pack format.
-== Format
+The format is created and read by the linkgit:git-bundle[1] command,
+and supported by e.g. linkgit:git-fetch[1] and linkgit:git-clone[1].
+
+
+FORMAT
+------
We will use ABNF notation to define the Git bundle format. See
-protocol-common.txt for the details.
+linkgit:gitprotocol-common[5] for the details.
A v2 bundle looks like this:
@@ -36,7 +58,9 @@ value = *(%01-09 / %0b-FF)
pack = ... ; packfile
----
-== Semantics
+
+SEMANTICS
+---------
A Git bundle consists of several parts.
@@ -62,13 +86,15 @@ In the bundle format, there can be a comment following a prerequisite obj-id.
This is a comment and it has no specific meaning. The writer of the bundle MAY
put any string here. The reader of the bundle MUST ignore the comment.
-=== Note on the shallow clone and a Git bundle
+Note on the shallow clone and a Git bundle
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note that the prerequisites does not represent a shallow-clone boundary. The
semantics of the prerequisites and the shallow-clone boundaries are different,
and the Git bundle v2 format cannot represent a shallow clone repository.
-== Capabilities
+CAPABILITIES
+------------
Because there is no opportunity for negotiation, unknown capabilities cause 'git
bundle' to abort.
@@ -79,3 +105,7 @@ bundle' to abort.
* `filter` specifies an object filter as in the `--filter` option in
linkgit:git-rev-list[1]. The resulting pack-file must be marked as a
`.promisor` pack-file after it is unbundled.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitformat-chunk.html b/gitformat-chunk.html
new file mode 100644
index 000000000..a38231614
--- /dev/null
+++ b/gitformat-chunk.html
@@ -0,0 +1,895 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitformat-chunk(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitformat-chunk(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitformat-chunk -
+ Chunk-based file formats
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Used by <a href="gitformat-commit-graph.html">gitformat-commit-graph(5)</a> and the "MIDX" format (see
+the pack format documentation in <a href="gitformat-pack.html">gitformat-pack(5)</a>).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Some file formats in Git use a common concept of "chunks" to describe
+sections of the file. This allows structured access to a large file by
+scanning a small "table of contents" for the remaining data. This common
+format is used by the <code>commit-graph</code> and <code>multi-pack-index</code> files. See
+the <code>multi-pack-index</code> format in <a href="gitformat-pack.html">gitformat-pack(5)</a> and
+the <code>commit-graph</code> format in <a href="gitformat-commit-graph.html">gitformat-commit-graph(5)</a> for
+how they use the chunks to describe structured data.</p></div>
+<div class="paragraph"><p>A chunk-based file format begins with some header information custom to
+that format. That header should include enough information to identify
+the file type, format version, and number of chunks in the file. From this
+information, that file can determine the start of the chunk-based region.</p></div>
+<div class="paragraph"><p>The chunk-based region starts with a table of contents describing where
+each chunk starts and ends. This consists of (C+1) rows of 12 bytes each,
+where C is the number of chunks. Consider the following table:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>| Chunk ID (4 bytes) | Chunk Offset (8 bytes) |
+|--------------------|------------------------|
+| ID[0] | OFFSET[0] |
+| ... | ... |
+| ID[C] | OFFSET[C] |
+| 0x0000 | OFFSET[C+1] |</code></pre>
+</div></div>
+<div class="paragraph"><p>Each row consists of a 4-byte chunk identifier (ID) and an 8-byte offset.
+Each integer is stored in network-byte order.</p></div>
+<div class="paragraph"><p>The chunk identifier <code>ID[i]</code> is a label for the data stored within this
+fill from <code>OFFSET[i]</code> (inclusive) to <code>OFFSET[i+1]</code> (exclusive). Thus, the
+size of the <code>i`th chunk is equal to the difference between `OFFSET[i+1]</code>
+and <code>OFFSET[i]</code>. This requires that the chunk data appears contiguously
+in the same order as the table of contents.</p></div>
+<div class="paragraph"><p>The final entry in the table of contents must be four zero bytes. This
+confirms that the table of contents is ending and provides the offset for
+the end of the chunk-based data.</p></div>
+<div class="paragraph"><p>Note: The chunk-based format expects that the file contains <em>at least</em> a
+trailing hash after <code>OFFSET[C+1]</code>.</p></div>
+<div class="paragraph"><p>Functions for working with chunk-based file formats are declared in
+<code>chunk-format.h</code>. Using these methods provide extra checks that assist
+developers when creating new file formats.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_writing_chunk_based_file_formats">Writing chunk-based file formats</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>To write a chunk-based file format, create a <code>struct chunkfile</code> by
+calling <code>init_chunkfile()</code> and pass a <code>struct hashfile</code> pointer. The
+caller is responsible for opening the <code>hashfile</code> and writing header
+information so the file format is identifiable before the chunk-based
+format begins.</p></div>
+<div class="paragraph"><p>Then, call <code>add_chunk()</code> for each chunk that is intended for write. This
+populates the <code>chunkfile</code> with information about the order and size of
+each chunk to write. Provide a <code>chunk_write_fn</code> function pointer to
+perform the write of the chunk data upon request.</p></div>
+<div class="paragraph"><p>Call <code>write_chunkfile()</code> to write the table of contents to the <code>hashfile</code>
+followed by each of the chunks. This will verify that each chunk wrote
+the expected amount of data so the table of contents is correct.</p></div>
+<div class="paragraph"><p>Finally, call <code>free_chunkfile()</code> to clear the <code>struct chunkfile</code> data. The
+caller is responsible for finalizing the <code>hashfile</code> by writing the trailing
+hash and closing the file.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_reading_chunk_based_file_formats">Reading chunk-based file formats</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>To read a chunk-based file format, the file must be opened as a
+memory-mapped region. The chunk-format API expects that the entire file
+is mapped as a contiguous memory region.</p></div>
+<div class="paragraph"><p>Initialize a <code>struct chunkfile</code> pointer with <code>init_chunkfile(NULL)</code>.</p></div>
+<div class="paragraph"><p>After reading the header information from the beginning of the file,
+including the chunk count, call <code>read_table_of_contents()</code> to populate
+the <code>struct chunkfile</code> with the list of chunks, their offsets, and their
+sizes.</p></div>
+<div class="paragraph"><p>Extract the data information for each chunk using <code>pair_chunk()</code> or
+<code>read_chunk()</code>:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+<code>pair_chunk()</code> assigns a given pointer with the location inside the
+ memory-mapped file corresponding to that chunk&#8217;s offset. If the chunk
+ does not exist, then the pointer is not modified.
+</p>
+</li>
+<li>
+<p>
+<code>read_chunk()</code> takes a <code>chunk_read_fn</code> function pointer and calls it
+ with the appropriate initial pointer and size information. The function
+ is not called if the chunk does not exist. Use this method to read chunks
+ if you need to perform immediate parsing or if you need to execute logic
+ based on the size of the chunk.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>After calling these methods, call <code>free_chunkfile()</code> to clear the
+<code>struct chunkfile</code> data. This will not close the memory-mapped region.
+Callers are expected to own that data for the timeframe the pointers into
+the region are needed.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">Examples</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>These file formats use the chunk-format API, and can be used as examples
+for future formats:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+<strong>commit-graph:</strong> see <code>write_commit_graph_file()</code> and <code>parse_commit_graph()</code>
+ in <code>commit-graph.c</code> for how the chunk-format API is used to write and
+ parse the commit-graph file format documented in
+ the commit-graph file format in <a href="gitformat-commit-graph.html">gitformat-commit-graph(5)</a>.
+</p>
+</li>
+<li>
+<p>
+<strong>multi-pack-index:</strong> see <code>write_midx_internal()</code> and <code>load_multi_pack_index()</code>
+ in <code>midx.c</code> for how the chunk-format API is used to write and
+ parse the multi-pack-index file format documented in
+ the multi-pack-index file format section of <a href="gitformat-pack.html">gitformat-pack(5)</a>.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/chunk-format.txt b/gitformat-chunk.txt
index 593614fce..57202ede2 100644
--- a/technical/chunk-format.txt
+++ b/gitformat-chunk.txt
@@ -1,12 +1,25 @@
-Chunk-based file formats
-========================
+gitformat-chunk(5)
+==================
+
+NAME
+----
+gitformat-chunk - Chunk-based file formats
+
+SYNOPSIS
+--------
+
+Used by linkgit:gitformat-commit-graph[5] and the "MIDX" format (see
+the pack format documentation in linkgit:gitformat-pack[5]).
+
+DESCRIPTION
+-----------
Some file formats in Git use a common concept of "chunks" to describe
sections of the file. This allows structured access to a large file by
scanning a small "table of contents" for the remaining data. This common
format is used by the `commit-graph` and `multi-pack-index` files. See
-link:technical/pack-format.html[the `multi-pack-index` format] and
-link:technical/commit-graph-format.html[the `commit-graph` format] for
+the `multi-pack-index` format in linkgit:gitformat-pack[5] and
+the `commit-graph` format in linkgit:gitformat-commit-graph[5] for
how they use the chunks to describe structured data.
A chunk-based file format begins with some header information custom to
@@ -108,9 +121,13 @@ for future formats:
* *commit-graph:* see `write_commit_graph_file()` and `parse_commit_graph()`
in `commit-graph.c` for how the chunk-format API is used to write and
parse the commit-graph file format documented in
- link:technical/commit-graph-format.html[the commit-graph file format].
+ the commit-graph file format in linkgit:gitformat-commit-graph[5].
* *multi-pack-index:* see `write_midx_internal()` and `load_multi_pack_index()`
in `midx.c` for how the chunk-format API is used to write and
parse the multi-pack-index file format documented in
- link:technical/pack-format.html[the multi-pack-index file format].
+ the multi-pack-index file format section of linkgit:gitformat-pack[5].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitformat-commit-graph.html b/gitformat-commit-graph.html
new file mode 100644
index 000000000..6db4b769a
--- /dev/null
+++ b/gitformat-commit-graph.html
@@ -0,0 +1,1083 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitformat-commit-graph(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitformat-commit-graph(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitformat-commit-graph -
+ Git commit graph format
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">$GIT_DIR/objects/info/commit-graph
+$GIT_DIR/objects/info/commit-graphs/*</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Git commit graph stores a list of commit OIDs and some associated
+metadata, including:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+The generation number of the commit.
+</p>
+</li>
+<li>
+<p>
+The root tree OID.
+</p>
+</li>
+<li>
+<p>
+The commit date.
+</p>
+</li>
+<li>
+<p>
+The parents of the commit, stored using positional references within
+ the graph file.
+</p>
+</li>
+<li>
+<p>
+The Bloom filter of the commit carrying the paths that were changed between
+ the commit and its first parent, if requested.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>These positional references are stored as unsigned 32-bit integers
+corresponding to the array position within the list of commit OIDs. Due
+to some special constants we use to track parents, we can store at most
+(1 &lt;&lt; 30) + (1 &lt;&lt; 29) + (1 &lt;&lt; 28) - 1 (around 1.8 billion) commits.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_commit_graph_files_have_the_following_format">Commit graph files have the following format:</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>In order to allow extensions that add extra data to the graph, we organize
+the body into "chunks" and provide a binary lookup table at the beginning
+of the body. The header includes certain values, such as number of chunks
+and hash type.</p></div>
+<div class="paragraph"><p>All multi-byte numbers are in network byte order.</p></div>
+<div class="sect2">
+<h3 id="_header">HEADER:</h3>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte signature:
+ The signature is: {'C', 'G', 'P', 'H'}</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-byte version number:
+ Currently, the only valid version is 1.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-byte Hash Version
+ We infer the hash length (H) from this value:
+ 1 =&gt; SHA-1
+ 2 =&gt; SHA-256
+ If the hash type does not match the repository's hash algorithm, the
+ commit-graph file should be ignored with a warning presented to the
+ user.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-byte number (C) of "chunks"</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-byte number (B) of base commit-graphs
+ We infer the length (H*B) of the Base Graphs chunk
+ from this value.</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_chunk_lookup">CHUNK LOOKUP:</h3>
+<div class="literalblock">
+<div class="content">
+<pre><code>(C + 1) * 12 bytes listing the table of contents for the chunks:
+ First 4 bytes describe the chunk id. Value 0 is a terminating label.
+ Other 8 bytes provide the byte-offset in current file for chunk to
+ start. (Chunks are ordered contiguously in the file, so you can infer
+ the length using the next chunk position if necessary.) Each chunk
+ ID appears at most once.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The CHUNK LOOKUP matches the table of contents from
+the chunk-based file format, see linkgit:gitformat-chunk[5]</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The remaining data in the body is described one chunk at a time, and
+these chunks may be given in any order. Chunks are required unless
+otherwise specified.</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_chunk_data">CHUNK DATA:</h3>
+<div class="sect3">
+<h4 id="_oid_fanout_id_em_o_em_em_i_em_em_d_em_em_f_em_256_4_bytes">OID Fanout (ID: {<em>O</em>, <em>I</em>, <em>D</em>, <em>F</em>}) (256 * 4 bytes)</h4>
+<div class="literalblock">
+<div class="content">
+<pre><code>The ith entry, F[i], stores the number of OIDs with first
+byte at most i. Thus F[255] stores the total
+number of commits (N).</code></pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_oid_lookup_id_em_o_em_em_i_em_em_d_em_em_l_em_n_h_bytes">OID Lookup (ID: {<em>O</em>, <em>I</em>, <em>D</em>, <em>L</em>}) (N * H bytes)</h4>
+<div class="literalblock">
+<div class="content">
+<pre><code>The OIDs for all commits in the graph, sorted in ascending order.</code></pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_commit_data_id_em_c_em_em_d_em_em_a_em_em_t_em_n_h_16_bytes">Commit Data (ID: {<em>C</em>, <em>D</em>, <em>A</em>, <em>T</em> }) (N * (H + 16) bytes)</h4>
+<div class="ulist"><ul>
+<li>
+<p>
+The first H bytes are for the OID of the root tree.
+</p>
+</li>
+<li>
+<p>
+The next 8 bytes are for the positions of the first two parents
+ of the ith commit. Stores value 0x70000000 if no parent in that
+ position. If there are more than two parents, the second value
+ has its most-significant bit on and the other bits store an array
+ position into the Extra Edge List chunk.
+</p>
+</li>
+<li>
+<p>
+The next 8 bytes store the topological level (generation number v1)
+ of the commit and
+ the commit time in seconds since EPOCH. The generation number
+ uses the higher 30 bits of the first 4 bytes, while the commit
+ time uses the 32 bits of the second 4 bytes, along with the lowest
+ 2 bits of the lowest byte, storing the 33rd and 34th bit of the
+ commit time.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect3">
+<h4 id="_generation_data_id_em_g_em_em_d_em_em_a_em_em_2_em_n_4_bytes_optional">Generation Data (ID: {<em>G</em>, <em>D</em>, <em>A</em>, <em>2</em> }) (N * 4 bytes) [Optional]</h4>
+<div class="ulist"><ul>
+<li>
+<p>
+This list of 4-byte values store corrected commit date offsets for the
+ commits, arranged in the same order as commit data chunk.
+</p>
+</li>
+<li>
+<p>
+If the corrected commit date offset cannot be stored within 31 bits,
+ the value has its most-significant bit on and the other bits store
+ the position of corrected commit date into the Generation Data Overflow
+ chunk.
+</p>
+</li>
+<li>
+<p>
+Generation Data chunk is present only when commit-graph file is written
+ by compatible versions of Git and in case of split commit-graph chains,
+ the topmost layer also has Generation Data chunk.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect3">
+<h4 id="_generation_data_overflow_id_em_g_em_em_d_em_em_o_em_em_2_em_optional">Generation Data Overflow (ID: {<em>G</em>, <em>D</em>, <em>O</em>, <em>2</em> }) [Optional]</h4>
+<div class="ulist"><ul>
+<li>
+<p>
+This list of 8-byte values stores the corrected commit date offsets
+ for commits with corrected commit date offsets that cannot be
+ stored within 31 bits.
+</p>
+</li>
+<li>
+<p>
+Generation Data Overflow chunk is present only when Generation Data
+ chunk is present and atleast one corrected commit date offset cannot
+ be stored within 31 bits.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect3">
+<h4 id="_extra_edge_list_id_em_e_em_em_d_em_em_g_em_em_e_em_optional">Extra Edge List (ID: {<em>E</em>, <em>D</em>, <em>G</em>, <em>E</em>}) [Optional]</h4>
+<div class="literalblock">
+<div class="content">
+<pre><code>This list of 4-byte values store the second through nth parents for
+all octopus merges. The second parent value in the commit data stores
+an array position within this list along with the most-significant bit
+on. Starting at that array position, iterate through this list of commit
+positions for the parents until reaching a value with the most-significant
+bit on. The other bits correspond to the position of the last parent.</code></pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_bloom_filter_index_id_em_b_em_em_i_em_em_d_em_em_x_em_n_4_bytes_optional">Bloom Filter Index (ID: {<em>B</em>, <em>I</em>, <em>D</em>, <em>X</em>}) (N * 4 bytes) [Optional]</h4>
+<div class="ulist"><ul>
+<li>
+<p>
+The ith entry, BIDX[i], stores the number of bytes in all Bloom filters
+ from commit 0 to commit i (inclusive) in lexicographic order. The Bloom
+ filter for the i-th commit spans from BIDX[i-1] to BIDX[i] (plus header
+ length), where BIDX[-1] is 0.
+</p>
+</li>
+<li>
+<p>
+The BIDX chunk is ignored if the BDAT chunk is not present.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect3">
+<h4 id="_bloom_filter_data_id_em_b_em_em_d_em_em_a_em_em_t_em_optional">Bloom Filter Data (ID: {<em>B</em>, <em>D</em>, <em>A</em>, <em>T</em>}) [Optional]</h4>
+<div class="ulist"><ul>
+<li>
+<p>
+It starts with header consisting of three unsigned 32-bit integers:
+</p>
+<div class="ulist"><ul>
+<li>
+<p>
+Version of the hash algorithm being used. We currently only support
+ value 1 which corresponds to the 32-bit version of the murmur3 hash
+ implemented exactly as described in
+ <a href="https://en.wikipedia.org/wiki/MurmurHash#Algorithm">https://en.wikipedia.org/wiki/MurmurHash#Algorithm</a> and the double
+ hashing technique using seed values 0x293ae76f and 0x7e646e2 as
+ described in <a href="https://doi.org/10.1007/978-3-540-30494-4_26">https://doi.org/10.1007/978-3-540-30494-4_26</a> "Bloom Filters
+ in Probabilistic Verification"
+</p>
+</li>
+<li>
+<p>
+The number of times a path is hashed and hence the number of bit positions
+ that cumulatively determine whether a file is present in the commit.
+</p>
+</li>
+<li>
+<p>
+The minimum number of bits <em>b</em> per entry in the Bloom filter. If the filter
+ contains <em>n</em> entries, then the filter size is the minimum number of 64-bit
+ words that contain n*b bits.
+</p>
+</li>
+</ul></div>
+</li>
+<li>
+<p>
+The rest of the chunk is the concatenation of all the computed Bloom
+ filters for the commits in lexicographic order.
+</p>
+</li>
+<li>
+<p>
+Note: Commits with no changes or more than 512 changes have Bloom filters
+ of length one, with either all bits set to zero or one respectively.
+</p>
+</li>
+<li>
+<p>
+The BDAT chunk is present if and only if BIDX is present.
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect3">
+<h4 id="_base_graphs_list_id_em_b_em_em_a_em_em_s_em_em_e_em_optional">Base Graphs List (ID: {<em>B</em>, <em>A</em>, <em>S</em>, <em>E</em>}) [Optional]</h4>
+<div class="literalblock">
+<div class="content">
+<pre><code>This list of H-byte hashes describe a set of B commit-graph files that
+form a commit-graph chain. The graph position for the ith commit in this
+file's OID Lookup chunk is equal to i plus the number of commits in all
+base graphs. If B is non-zero, this chunk must exist.</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_trailer">TRAILER:</h3>
+<div class="literalblock">
+<div class="content">
+<pre><code>H-byte HASH-checksum of all of the above.</code></pre>
+</div></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_historical_notes">Historical Notes:</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Generation Data (GDA2) and Generation Data Overflow (GDO2) chunks have
+the number <em>2</em> in their chunk IDs because a previous version of Git wrote
+possibly erroneous data in these chunks with the IDs "GDAT" and "GDOV". By
+changing the IDs, newer versions of Git will silently ignore those older
+chunks and write the new information without trusting the incorrect data.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/commit-graph-format.txt b/gitformat-commit-graph.txt
index 484b185ba..732466571 100644
--- a/technical/commit-graph-format.txt
+++ b/gitformat-commit-graph.txt
@@ -1,5 +1,18 @@
-Git commit graph format
-=======================
+gitformat-commit-graph(5)
+=========================
+
+NAME
+----
+gitformat-commit-graph - Git commit graph format
+
+SYNOPSIS
+--------
+[verse]
+$GIT_DIR/objects/info/commit-graph
+$GIT_DIR/objects/info/commit-graphs/*
+
+DESCRIPTION
+-----------
The Git commit graph stores a list of commit OIDs and some associated
metadata, including:
@@ -30,7 +43,7 @@ and hash type.
All multi-byte numbers are in network byte order.
-HEADER:
+=== HEADER:
4-byte signature:
The signature is: {'C', 'G', 'P', 'H'}
@@ -52,7 +65,7 @@ HEADER:
We infer the length (H*B) of the Base Graphs chunk
from this value.
-CHUNK LOOKUP:
+=== CHUNK LOOKUP:
(C + 1) * 12 bytes listing the table of contents for the chunks:
First 4 bytes describe the chunk id. Value 0 is a terminating label.
@@ -62,23 +75,23 @@ CHUNK LOOKUP:
ID appears at most once.
The CHUNK LOOKUP matches the table of contents from
- link:technical/chunk-format.html[the chunk-based file format].
+ the chunk-based file format, see linkgit:gitformat-chunk[5]
The remaining data in the body is described one chunk at a time, and
these chunks may be given in any order. Chunks are required unless
otherwise specified.
-CHUNK DATA:
+=== CHUNK DATA:
- OID Fanout (ID: {'O', 'I', 'D', 'F'}) (256 * 4 bytes)
+==== OID Fanout (ID: {'O', 'I', 'D', 'F'}) (256 * 4 bytes)
The ith entry, F[i], stores the number of OIDs with first
byte at most i. Thus F[255] stores the total
number of commits (N).
- OID Lookup (ID: {'O', 'I', 'D', 'L'}) (N * H bytes)
+==== OID Lookup (ID: {'O', 'I', 'D', 'L'}) (N * H bytes)
The OIDs for all commits in the graph, sorted in ascending order.
- Commit Data (ID: {'C', 'D', 'A', 'T' }) (N * (H + 16) bytes)
+==== Commit Data (ID: {'C', 'D', 'A', 'T' }) (N * (H + 16) bytes)
* The first H bytes are for the OID of the root tree.
* The next 8 bytes are for the positions of the first two parents
of the ith commit. Stores value 0x70000000 if no parent in that
@@ -93,7 +106,7 @@ CHUNK DATA:
2 bits of the lowest byte, storing the 33rd and 34th bit of the
commit time.
- Generation Data (ID: {'G', 'D', 'A', '2' }) (N * 4 bytes) [Optional]
+==== Generation Data (ID: {'G', 'D', 'A', '2' }) (N * 4 bytes) [Optional]
* This list of 4-byte values store corrected commit date offsets for the
commits, arranged in the same order as commit data chunk.
* If the corrected commit date offset cannot be stored within 31 bits,
@@ -104,7 +117,7 @@ CHUNK DATA:
by compatible versions of Git and in case of split commit-graph chains,
the topmost layer also has Generation Data chunk.
- Generation Data Overflow (ID: {'G', 'D', 'O', '2' }) [Optional]
+==== Generation Data Overflow (ID: {'G', 'D', 'O', '2' }) [Optional]
* This list of 8-byte values stores the corrected commit date offsets
for commits with corrected commit date offsets that cannot be
stored within 31 bits.
@@ -112,7 +125,7 @@ CHUNK DATA:
chunk is present and atleast one corrected commit date offset cannot
be stored within 31 bits.
- Extra Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional]
+==== Extra Edge List (ID: {'E', 'D', 'G', 'E'}) [Optional]
This list of 4-byte values store the second through nth parents for
all octopus merges. The second parent value in the commit data stores
an array position within this list along with the most-significant bit
@@ -120,14 +133,14 @@ CHUNK DATA:
positions for the parents until reaching a value with the most-significant
bit on. The other bits correspond to the position of the last parent.
- Bloom Filter Index (ID: {'B', 'I', 'D', 'X'}) (N * 4 bytes) [Optional]
+==== Bloom Filter Index (ID: {'B', 'I', 'D', 'X'}) (N * 4 bytes) [Optional]
* The ith entry, BIDX[i], stores the number of bytes in all Bloom filters
from commit 0 to commit i (inclusive) in lexicographic order. The Bloom
filter for the i-th commit spans from BIDX[i-1] to BIDX[i] (plus header
length), where BIDX[-1] is 0.
* The BIDX chunk is ignored if the BDAT chunk is not present.
- Bloom Filter Data (ID: {'B', 'D', 'A', 'T'}) [Optional]
+==== Bloom Filter Data (ID: {'B', 'D', 'A', 'T'}) [Optional]
* It starts with header consisting of three unsigned 32-bit integers:
- Version of the hash algorithm being used. We currently only support
value 1 which corresponds to the 32-bit version of the murmur3 hash
@@ -147,13 +160,13 @@ CHUNK DATA:
of length one, with either all bits set to zero or one respectively.
* The BDAT chunk is present if and only if BIDX is present.
- Base Graphs List (ID: {'B', 'A', 'S', 'E'}) [Optional]
+==== Base Graphs List (ID: {'B', 'A', 'S', 'E'}) [Optional]
This list of H-byte hashes describe a set of B commit-graph files that
form a commit-graph chain. The graph position for the ith commit in this
file's OID Lookup chunk is equal to i plus the number of commits in all
base graphs. If B is non-zero, this chunk must exist.
-TRAILER:
+=== TRAILER:
H-byte HASH-checksum of all of the above.
@@ -164,3 +177,7 @@ the number '2' in their chunk IDs because a previous version of Git wrote
possibly erroneous data in these chunks with the IDs "GDAT" and "GDOV". By
changing the IDs, newer versions of Git will silently ignore those older
chunks and write the new information without trusting the incorrect data.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitformat-index.html b/gitformat-index.html
new file mode 100644
index 000000000..c8b0a684e
--- /dev/null
+++ b/gitformat-index.html
@@ -0,0 +1,1496 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitformat-index(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitformat-index(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitformat-index -
+ Git index format
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">$GIT_DIR/index</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Git index format</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_the_git_index_file_has_the_following_format">The Git index file has the following format</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>All binary numbers are in network byte order.
+In a repository using the traditional SHA-1, checksums and object IDs
+(object names) mentioned below are all computed using SHA-1. Similarly,
+in SHA-256 repositories, these values are computed using SHA-256.
+Version 2 is described here unless stated otherwise.</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+A 12-byte header consisting of
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte signature:
+ The signature is { 'D', 'I', 'R', 'C' } (stands for "dircache")</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte version number:
+ The current supported versions are 2, 3 and 4.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit number of index entries.</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+A number of sorted index entries (see below).
+</p>
+</li>
+<li>
+<p>
+Extensions
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>Extensions are identified by signature. Optional extensions can
+be ignored if Git does not understand them.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte extension signature. If the first byte is 'A'..'Z' the
+extension is optional and can be ignored.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit size of the extension</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Extension data</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Hash checksum over the content of the index file before this checksum.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_index_entry">Index entry</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>Index entries are sorted in ascending order on the name field,
+interpreted as a string of unsigned bytes (i.e. memcmp() order, no
+localization, no special casing of directory separator '/'). Entries
+with the same name are sorted by their stage field.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>An index entry typically represents a file. However, if sparse-checkout
+is enabled in cone mode (`core.sparseCheckoutCone` is enabled) and the
+`extensions.sparseIndex` extension is enabled, then the index may
+contain entries for directories outside of the sparse-checkout definition.
+These entries have mode `040000`, include the `SKIP_WORKTREE` bit, and
+the path ends in a directory separator.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit ctime seconds, the last time a file's metadata changed
+ this is stat(2) data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit ctime nanosecond fractions
+ this is stat(2) data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit mtime seconds, the last time a file's data changed
+ this is stat(2) data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit mtime nanosecond fractions
+ this is stat(2) data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit dev
+ this is stat(2) data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit ino
+ this is stat(2) data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit mode, split into (high to low bits)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-bit object type
+ valid values in binary are 1000 (regular file), 1010 (symbolic link)
+ and 1110 (gitlink)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>3-bit unused</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>9-bit unix permission. Only 0755 and 0644 are valid for regular files.
+Symbolic links and gitlinks have value 0 in this field.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit uid
+ this is stat(2) data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit gid
+ this is stat(2) data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>32-bit file size
+ This is the on-disk size from stat(2), truncated to 32-bit.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Object name for the represented object</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>A 16-bit 'flags' field split into (high to low bits)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-bit assume-valid flag</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-bit extended flag (must be zero in version 2)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>2-bit stage (during merge)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>12-bit name length if the length is less than 0xFFF; otherwise 0xFFF
+is stored in this field.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>(Version 3 or later) A 16-bit field, only applicable if the
+"extended flag" above is 1, split into (high to low bits).</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-bit reserved for future</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-bit skip-worktree flag (used by sparse checkout)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-bit intent-to-add flag (used by "git add -N")</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>13-bit unused, must be zero</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Entry path name (variable length) relative to top level directory
+ (without leading slash). '/' is used as path separator. The special
+ path components ".", ".." and ".git" (without quotes) are disallowed.
+ Trailing slash is also disallowed.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The exact encoding is undefined, but the '.' and '/' characters
+are encoded in 7-bit ASCII and the encoding cannot contain a NUL
+byte (iow, this is a UNIX pathname).</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>(Version 4) In version 4, the entry path name is prefix-compressed
+ relative to the path name for the previous entry (the very first
+ entry is encoded as if the path name for the previous entry is an
+ empty string). At the beginning of an entry, an integer N in the
+ variable width encoding (the same encoding as the offset is encoded
+ for OFS_DELTA pack entries; see linkgit:gitformat-pack[5]) is stored, followed
+ by a NUL-terminated string S. Removing N bytes from the end of the
+ path name for the previous entry, and replacing it with the string S
+ yields the path name for this entry.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-8 nul bytes as necessary to pad the entry to a multiple of eight bytes
+while keeping the name NUL-terminated.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>(Version 4) In version 4, the padding after the pathname does not
+exist.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Interpretation of index entries in split index mode is completely
+different. See below for details.</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_extensions">Extensions</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_cache_tree">Cache tree</h3>
+<div class="literalblock">
+<div class="content">
+<pre><code>Since the index does not record entries for directories, the cache
+entries cannot describe tree objects that already exist in the object
+database for regions of the index that are unchanged from an existing
+commit. The cache tree extension stores a recursive tree structure that
+describes the trees that already exist and completely match sections of
+the cache entries. This speeds up tree object generation from the index
+for a new commit by only computing the trees that are "new" to that
+commit. It also assists when comparing the index to another tree, such
+as `HEAD^{tree}`, since sections of the index can be skipped when a tree
+comparison demonstrates equality.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The recursive tree structure uses nodes that store a number of cache
+entries, a list of subnodes, and an object ID (OID). The OID references
+the existing tree for that node, if it is known to exist. The subnodes
+correspond to subdirectories that themselves have cache tree nodes. The
+number of cache entries corresponds to the number of cache entries in
+the index that describe paths within that tree's directory.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The extension tracks the full directory structure in the cache tree
+extension, but this is generally smaller than the full cache entry list.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>When a path is updated in index, Git invalidates all nodes of the
+recursive cache tree corresponding to the parent directories of that
+path. We store these tree nodes as being "invalid" by using "-1" as the
+number of cache entries. Invalid nodes still store a span of index
+entries, allowing Git to focus its efforts when reconstructing a full
+cache tree.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The signature for this extension is { 'T', 'R', 'E', 'E' }.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>A series of entries fill the entire extension; each of which
+consists of:</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+NUL-terminated path component (relative to its parent directory);
+</p>
+</li>
+<li>
+<p>
+ASCII decimal number of entries in the index that is covered by the
+ tree this entry represents (entry_count);
+</p>
+</li>
+<li>
+<p>
+A space (ASCII 32);
+</p>
+</li>
+<li>
+<p>
+ASCII decimal number that represents the number of subtrees this
+ tree has;
+</p>
+</li>
+<li>
+<p>
+A newline (ASCII 10); and
+</p>
+</li>
+<li>
+<p>
+Object name for the object that would result from writing this span
+ of index as a tree.
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>An entry can be in an invalidated state and is represented by having
+a negative number in the entry_count field. In this case, there is no
+object name and the next entry starts immediately after the newline.
+When writing an invalid entry, -1 should always be used as entry_count.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The entries are written out in the top-down, depth-first order. The
+first entry represents the root level of the repository, followed by the
+first subtree--let's call this A--of the root level (with its name
+relative to the root level), followed by the first subtree of A (with
+its name relative to A), and so on. The specified number of subtrees
+indicates when the current level of the recursive stack is complete.</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_resolve_undo">Resolve undo</h3>
+<div class="literalblock">
+<div class="content">
+<pre><code>A conflict is represented in the index as a set of higher stage entries.
+When a conflict is resolved (e.g. with "git add path"), these higher
+stage entries will be removed and a stage-0 entry with proper resolution
+is added.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>When these higher stage entries are removed, they are saved in the
+resolve undo extension, so that conflicts can be recreated (e.g. with
+"git checkout -m"), in case users want to redo a conflict resolution
+from scratch.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The signature for this extension is { 'R', 'E', 'U', 'C' }.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>A series of entries fill the entire extension; each of which
+consists of:</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+NUL-terminated pathname the entry describes (relative to the root of
+ the repository, i.e. full pathname);
+</p>
+</li>
+<li>
+<p>
+Three NUL-terminated ASCII octal numbers, entry mode of entries in
+ stage 1 to 3 (a missing stage is represented by "0" in this field);
+ and
+</p>
+</li>
+<li>
+<p>
+At most three object names of the entry in stages from 1 to 3
+ (nothing is written for a missing stage).
+</p>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_split_index">Split index</h3>
+<div class="literalblock">
+<div class="content">
+<pre><code>In split index mode, the majority of index entries could be stored
+in a separate file. This extension records the changes to be made on
+top of that to produce the final index.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The signature for this extension is { 'l', 'i', 'n', 'k' }.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The extension consists of:</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Hash of the shared index file. The shared index file path
+ is $GIT_DIR/sharedindex.&lt;hash&gt;. If all bits are zero, the
+ index does not require a shared index file.
+</p>
+</li>
+<li>
+<p>
+An ewah-encoded delete bitmap, each bit represents an entry in the
+ shared index. If a bit is set, its corresponding entry in the
+ shared index will be removed from the final index. Note, because
+ a delete operation changes index entry positions, but we do need
+ original positions in replace phase, it&#8217;s best to just mark
+ entries for removal, then do a mass deletion after replacement.
+</p>
+</li>
+<li>
+<p>
+An ewah-encoded replace bitmap, each bit represents an entry in
+ the shared index. If a bit is set, its corresponding entry in the
+ shared index will be replaced with an entry in this index
+ file. All replaced entries are stored in sorted order in this
+ index. The first "1" bit in the replace bitmap corresponds to the
+ first index entry, the second "1" bit to the second entry and so
+ on. Replaced entries may have empty path names to save space.
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>The remaining index entries after replaced ones will be added to the
+final index. These added entries are also sorted by entry name then
+stage.</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_untracked_cache">Untracked cache</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>Untracked cache saves the untracked file list and necessary data to
+verify the cache. The signature for this extension is { 'U', 'N',
+'T', 'R' }.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The extension starts with</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+A sequence of NUL-terminated strings, preceded by the size of the
+ sequence in variable width encoding. Each string describes the
+ environment where the cache can be used.
+</p>
+</li>
+<li>
+<p>
+Stat data of $GIT_DIR/info/exclude. See "Index entry" section from
+ ctime field until "file size".
+</p>
+</li>
+<li>
+<p>
+Stat data of core.excludesFile
+</p>
+</li>
+<li>
+<p>
+32-bit dir_flags (see struct dir_struct)
+</p>
+</li>
+<li>
+<p>
+Hash of $GIT_DIR/info/exclude. A null hash means the file
+ does not exist.
+</p>
+</li>
+<li>
+<p>
+Hash of core.excludesFile. A null hash means the file does
+ not exist.
+</p>
+</li>
+<li>
+<p>
+NUL-terminated string of per-dir exclude file name. This usually
+ is ".gitignore".
+</p>
+</li>
+<li>
+<p>
+The number of following directory blocks, variable width
+ encoding. If this number is zero, the extension ends here with a
+ following NUL.
+</p>
+</li>
+<li>
+<p>
+A number of directory blocks in depth-first-search order, each
+ consists of
+</p>
+</li>
+<li>
+<p>
+The number of untracked entries, variable width encoding.
+</p>
+</li>
+<li>
+<p>
+The number of sub-directory blocks, variable width encoding.
+</p>
+</li>
+<li>
+<p>
+The directory name terminated by NUL.
+</p>
+</li>
+<li>
+<p>
+A number of untracked file/dir names terminated by NUL.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>The remaining data of each directory block is grouped by type:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+An ewah bitmap, the n-th bit marks whether the n-th directory has
+ valid untracked cache entries.
+</p>
+</li>
+<li>
+<p>
+An ewah bitmap, the n-th bit records "check-only" bit of
+ read_directory_recursive() for the n-th directory.
+</p>
+</li>
+<li>
+<p>
+An ewah bitmap, the n-th bit indicates whether hash and stat data
+ is valid for the n-th directory and exists in the next data.
+</p>
+</li>
+<li>
+<p>
+An array of stat data. The n-th data corresponds with the n-th
+ "one" bit in the previous ewah bitmap.
+</p>
+</li>
+<li>
+<p>
+An array of hashes. The n-th hash corresponds with the n-th "one" bit
+ in the previous ewah bitmap.
+</p>
+</li>
+<li>
+<p>
+One NUL.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_file_system_monitor_cache">File System Monitor cache</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>The file system monitor cache tracks files for which the core.fsmonitor
+hook has told us about changes. The signature for this extension is
+{ 'F', 'S', 'M', 'N' }.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The extension starts with</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+32-bit version number: the current supported versions are 1 and 2.
+</p>
+</li>
+<li>
+<p>
+(Version 1)
+ 64-bit time: the extension data reflects all changes through the given
+ time which is stored as the nanoseconds elapsed since midnight,
+ January 1, 1970.
+</p>
+</li>
+<li>
+<p>
+(Version 2)
+ A null terminated string: an opaque token defined by the file system
+ monitor application. The extension data reflects all changes relative
+ to that token.
+</p>
+</li>
+<li>
+<p>
+32-bit bitmap size: the size of the CE_FSMONITOR_VALID bitmap.
+</p>
+</li>
+<li>
+<p>
+An ewah bitmap, the n-th bit indicates whether the n-th index entry
+ is not CE_FSMONITOR_VALID.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_end_of_index_entry">End of Index Entry</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>The End of Index Entry (EOIE) is used to locate the end of the variable
+length index entries and the beginning of the extensions. Code can take
+advantage of this to quickly locate the index extensions without having
+to parse through all of the index entries.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Because it must be able to be loaded before the variable length cache
+entries and other index extensions, this extension must be written last.
+The signature for this extension is { 'E', 'O', 'I', 'E' }.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The extension consists of:</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+32-bit offset to the end of the index entries
+</p>
+</li>
+<li>
+<p>
+Hash over the extension types and their sizes (but not
+ their contents). E.g. if we have "TREE" extension that is N-bytes
+ long, "REUC" extension that is M-bytes long, followed by "EOIE",
+ then the hash would be:
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>Hash("TREE" + &lt;binary representation of N&gt; +
+ "REUC" + &lt;binary representation of M&gt;)</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_index_entry_offset_table">Index Entry Offset Table</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>The Index Entry Offset Table (IEOT) is used to help address the CPU
+cost of loading the index by enabling multi-threading the process of
+converting cache entries from the on-disk format to the in-memory format.
+The signature for this extension is { 'I', 'E', 'O', 'T' }.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The extension consists of:</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+32-bit version (currently 1)
+</p>
+</li>
+<li>
+<p>
+A number of index offset entries each consisting of:
+</p>
+</li>
+<li>
+<p>
+32-bit offset from the beginning of the file to the first cache entry
+ in this block of entries.
+</p>
+</li>
+<li>
+<p>
+32-bit count of cache entries in this block
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_sparse_directory_entries">Sparse Directory Entries</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>When using sparse-checkout in cone mode, some entire directories within
+the index can be summarized by pointing to a tree object instead of the
+entire expanded list of paths within that tree. An index containing such
+entries is a "sparse index". Index format versions 4 and less were not
+implemented with such entries in mind. Thus, for these versions, an
+index containing sparse directory entries will include this extension
+with signature { 's', 'd', 'i', 'r' }. Like the split-index extension,
+tools should avoid interacting with a sparse index unless they understand
+this extension.</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/index-format.txt b/gitformat-index.txt
index f691c20ab..015cb21bd 100644
--- a/technical/index-format.txt
+++ b/gitformat-index.txt
@@ -1,5 +1,19 @@
+gitformat-index(5)
+==================
+
+NAME
+----
+gitformat-index - Git index format
+
+SYNOPSIS
+--------
+[verse]
+$GIT_DIR/index
+
+DESCRIPTION
+-----------
+
Git index format
-================
== The Git index file has the following format
@@ -125,7 +139,7 @@ Git index format
entry is encoded as if the path name for the previous entry is an
empty string). At the beginning of an entry, an integer N in the
variable width encoding (the same encoding as the offset is encoded
- for OFS_DELTA pack entries; see pack-format.txt) is stored, followed
+ for OFS_DELTA pack entries; see linkgit:gitformat-pack[5]) is stored, followed
by a NUL-terminated string S. Removing N bytes from the end of the
path name for the previous entry, and replacing it with the string S
yields the path name for this entry.
@@ -402,3 +416,7 @@ The remaining data of each directory block is grouped by type:
with signature { 's', 'd', 'i', 'r' }. Like the split-index extension,
tools should avoid interacting with a sparse index unless they understand
this extension.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitformat-pack.html b/gitformat-pack.html
new file mode 100644
index 000000000..9d5429b6e
--- /dev/null
+++ b/gitformat-pack.html
@@ -0,0 +1,1602 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitformat-pack(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitformat-pack(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitformat-pack -
+ Git pack format
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">$GIT_DIR/objects/pack/pack-<strong>.{pack,idx}
+$GIT_DIR/objects/pack/pack-</strong>.rev
+$GIT_DIR/objects/pack/pack-*.mtimes
+$GIT_DIR/objects/pack/multi-pack-index</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Git pack format is now Git stores most of its primary repository
+data. Over the lietime af a repository loose objects (if any) and
+smaller packs are consolidated into larger pack(s). See
+<a href="git-gc.html">git-gc(1)</a> and <a href="git-pack-objects.html">git-pack-objects(1)</a>.</p></div>
+<div class="paragraph"><p>The pack format is also used over-the-wire, see
+e.g. <a href="gitprotocol-v2.html">gitprotocol-v2(5)</a>, as well as being a part of
+other container formats in the case of <a href="gitformat-bundle.html">gitformat-bundle(5)</a>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_checksums_and_object_ids">Checksums and object IDs</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>In a repository using the traditional SHA-1, pack checksums, index checksums,
+and object IDs (object names) mentioned below are all computed using SHA-1.
+Similarly, in SHA-256 repositories, these values are computed using SHA-256.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_pack_pack_files_have_the_following_format">pack-*.pack files have the following format:</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+A header appears at the beginning and consists of the following:
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte signature:
+ The signature is: {'P', 'A', 'C', 'K'}</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte version number (network byte order):
+ Git currently accepts version number 2 or 3 but
+ generates version 2 only.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte number of objects contained in the pack (network byte order)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Observation: we cannot have more than 4G versions ;-) and
+more than 4G objects in a pack.</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+The header is followed by number of object entries, each of
+ which looks like this:
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>(undeltified representation)
+n-byte type and length (3-bit type, (n-1)*7+4-bit length)
+compressed data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>(deltified representation)
+n-byte type and length (3-bit type, (n-1)*7+4-bit length)
+base object name if OBJ_REF_DELTA or a negative relative
+ offset from the delta object's position in the pack if this
+ is an OBJ_OFS_DELTA object
+compressed delta data</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Observation: length of each object is encoded in a variable
+length format and is not constrained to 32-bit or anything.</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+The trailer records a pack checksum of all of the above.
+</p>
+</li>
+</ul></div>
+<div class="sect2">
+<h3 id="_object_types">Object types</h3>
+<div class="paragraph"><p>Valid object types are:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+OBJ_COMMIT (1)
+</p>
+</li>
+<li>
+<p>
+OBJ_TREE (2)
+</p>
+</li>
+<li>
+<p>
+OBJ_BLOB (3)
+</p>
+</li>
+<li>
+<p>
+OBJ_TAG (4)
+</p>
+</li>
+<li>
+<p>
+OBJ_OFS_DELTA (6)
+</p>
+</li>
+<li>
+<p>
+OBJ_REF_DELTA (7)
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Type 5 is reserved for future expansion. Type 0 is invalid.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_size_encoding">Size encoding</h3>
+<div class="paragraph"><p>This document uses the following "size encoding" of non-negative
+integers: From each byte, the seven least significant bits are
+used to form the resulting integer. As long as the most significant
+bit is 1, this process continues; the byte with MSB 0 provides the
+last seven bits. The seven-bit chunks are concatenated. Later
+values are more significant.</p></div>
+<div class="paragraph"><p>This size encoding should not be confused with the "offset encoding",
+which is also used in this document.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_deltified_representation">Deltified representation</h3>
+<div class="paragraph"><p>Conceptually there are only four object types: commit, tree, tag and
+blob. However to save space, an object could be stored as a "delta" of
+another "base" object. These representations are assigned new types
+ofs-delta and ref-delta, which is only valid in a pack file.</p></div>
+<div class="paragraph"><p>Both ofs-delta and ref-delta store the "delta" to be applied to
+another object (called <em>base object</em>) to reconstruct the object. The
+difference between them is, ref-delta directly encodes base object
+name. If the base object is in the same pack, ofs-delta encodes
+the offset of the base object in the pack instead.</p></div>
+<div class="paragraph"><p>The base object could also be deltified if it&#8217;s in the same pack.
+Ref-delta can also refer to an object outside the pack (i.e. the
+so-called "thin pack"). When stored on disk however, the pack should
+be self contained to avoid cyclic dependency.</p></div>
+<div class="paragraph"><p>The delta data starts with the size of the base object and the
+size of the object to be reconstructed. These sizes are
+encoded using the size encoding from above. The remainder of
+the delta data is a sequence of instructions to reconstruct the object
+from the base object. If the base object is deltified, it must be
+converted to canonical form first. Each instruction appends more and
+more data to the target object until it&#8217;s complete. There are two
+supported instructions so far: one for copy a byte range from the
+source object and one for inserting new data embedded in the
+instruction itself.</p></div>
+<div class="paragraph"><p>Each instruction has variable length. Instruction type is determined
+by the seventh bit of the first octet. The following diagrams follow
+the convention in RFC 1951 (Deflate compressed data format).</p></div>
+<div class="sect3">
+<h4 id="_instruction_to_copy_from_base_object">Instruction to copy from base object</h4>
+<div class="literalblock">
+<div class="content">
+<pre><code>+----------+---------+---------+---------+---------+-------+-------+-------+
+| 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |
++----------+---------+---------+---------+---------+-------+-------+-------+</code></pre>
+</div></div>
+<div class="paragraph"><p>This is the instruction format to copy a byte range from the source
+object. It encodes the offset to copy from and the number of bytes to
+copy. Offset and size are in little-endian order.</p></div>
+<div class="paragraph"><p>All offset and size bytes are optional. This is to reduce the
+instruction size when encoding small offsets or sizes. The first seven
+bits in the first octet determines which of the next seven octets is
+present. If bit zero is set, offset1 is present. If bit one is set
+offset2 is present and so on.</p></div>
+<div class="paragraph"><p>Note that a more compact instruction does not change offset and size
+encoding. For example, if only offset2 is omitted like below, offset3
+still contains bits 16-23. It does not become offset2 and contains
+bits 8-15 even if it&#8217;s right next to offset1.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>+----------+---------+---------+
+| 10000101 | offset1 | offset3 |
++----------+---------+---------+</code></pre>
+</div></div>
+<div class="paragraph"><p>In its most compact form, this instruction only takes up one byte
+(0x80) with both offset and size omitted, which will have default
+values zero. There is another exception: size zero is automatically
+converted to 0x10000.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_instruction_to_add_new_data">Instruction to add new data</h4>
+<div class="literalblock">
+<div class="content">
+<pre><code>+----------+============+
+| 0xxxxxxx | data |
++----------+============+</code></pre>
+</div></div>
+<div class="paragraph"><p>This is the instruction to construct target object without the base
+object. The following data is appended to the target object. The first
+seven bits of the first octet determines the size of data in
+bytes. The size must be non-zero.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_reserved_instruction">Reserved instruction</h4>
+<div class="literalblock">
+<div class="content">
+<pre><code>+----------+============
+| 00000000 |
++----------+============</code></pre>
+</div></div>
+<div class="paragraph"><p>This is the instruction reserved for future expansion.</p></div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_original_version_1_pack_idx_files_have_the_following_format">Original (version 1) pack-*.idx files have the following format:</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+The header consists of 256 4-byte network byte order
+ integers. N-th entry of this table records the number of
+ objects in the corresponding pack, the first byte of whose
+ object name is less than or equal to N. This is called the
+ <em>first-level fan-out</em> table.
+</p>
+</li>
+<li>
+<p>
+The header is followed by sorted 24-byte entries, one entry
+ per object in the pack. Each entry is:
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte network byte order integer, recording where the
+object is stored in the packfile as the offset from the
+beginning.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>one object name of the appropriate size.</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+The file is concluded with a trailer:
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>A copy of the pack checksum at the end of the corresponding
+packfile.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Index checksum of all of the above.</code></pre>
+</div></div>
+</li>
+</ul></div>
+<div class="paragraph"><p>Pack Idx file:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code> -- +--------------------------------+
+fanout | fanout[0] = 2 (for example) |-.
+table +--------------------------------+ |
+ | fanout[1] | |
+ +--------------------------------+ |
+ | fanout[2] | |
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
+ | fanout[255] = total objects |---.
+ -- +--------------------------------+ | |
+main | offset | | |
+index | object name 00XXXXXXXXXXXXXXXX | | |
+table +--------------------------------+ | |
+ | offset | | |
+ | object name 00XXXXXXXXXXXXXXXX | | |
+ +--------------------------------+&lt;+ |
+ .-| offset | |
+ | | object name 01XXXXXXXXXXXXXXXX | |
+ | +--------------------------------+ |
+ | | offset | |
+ | | object name 01XXXXXXXXXXXXXXXX | |
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
+ | | offset | |
+ | | object name FFXXXXXXXXXXXXXXXX | |
+ --| +--------------------------------+&lt;--+
+trailer | | packfile checksum |
+ | +--------------------------------+
+ | | idxfile checksum |
+ | +--------------------------------+
+ .-------.
+ |
+Pack file entry: &lt;+</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>packed object header:
+ 1-byte size extension bit (MSB)
+ type (next 3 bit)
+ size0 (lower 4-bit)
+ n-byte sizeN (as long as MSB is set, each 7-bit)
+ size0..sizeN form 4+7+7+..+7 bit integer, size0
+ is the least significant part, and sizeN is the
+ most significant part.
+packed object data:
+ If it is not DELTA, then deflated bytes (the size above
+ is the size before compression).
+ If it is REF_DELTA, then
+ base object name (the size above is the
+ size of the delta data that follows).
+ delta data, deflated.
+ If it is OFS_DELTA, then
+ n-byte offset (see below) interpreted as a negative
+ offset from the type-byte of the header of the
+ ofs-delta entry (the size above is the size of
+ the delta data that follows).
+ delta data, deflated.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>offset encoding:
+ n bytes with MSB set in all but the last one.
+ The offset is then the number constructed by
+ concatenating the lower 7 bit of each byte, and
+ for n &gt;= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1))
+ to the result.</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_version_2_pack_idx_files_support_packs_larger_than_4_gib_and">Version 2 pack-*.idx files support packs larger than 4 GiB, and</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>have some other reorganizations. They have the format:</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+A 4-byte magic number <em>\377tOc</em> which is an unreasonable
+ fanout[0] value.
+</p>
+</li>
+<li>
+<p>
+A 4-byte version number (= 2)
+</p>
+</li>
+<li>
+<p>
+A 256-entry fan-out table just like v1.
+</p>
+</li>
+<li>
+<p>
+A table of sorted object names. These are packed together
+ without offset values to reduce the cache footprint of the
+ binary search for a specific object name.
+</p>
+</li>
+<li>
+<p>
+A table of 4-byte CRC32 values of the packed object data.
+ This is new in v2 so compressed data can be copied directly
+ from pack to pack during repacking without undetected
+ data corruption.
+</p>
+</li>
+<li>
+<p>
+A table of 4-byte offset values (in network byte order).
+ These are usually 31-bit pack file offsets, but large
+ offsets are encoded as an index into the next table with
+ the msbit set.
+</p>
+</li>
+<li>
+<p>
+A table of 8-byte offset entries (empty for pack files less
+ than 2 GiB). Pack files are organized with heavily used
+ objects toward the front, so most object references should
+ not need to refer to this table.
+</p>
+</li>
+<li>
+<p>
+The same trailer as a v1 pack file:
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>A copy of the pack checksum at the end of
+corresponding packfile.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Index checksum of all of the above.</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_pack_rev_files_have_the_format">pack-*.rev files have the format:</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+A 4-byte magic number <em>0x52494458</em> (<em>RIDX</em>).
+</p>
+</li>
+<li>
+<p>
+A 4-byte version identifier (= 1).
+</p>
+</li>
+<li>
+<p>
+A 4-byte hash function identifier (= 1 for SHA-1, 2 for SHA-256).
+</p>
+</li>
+<li>
+<p>
+A table of index positions (one per packed object, num_objects in
+ total, each a 4-byte unsigned integer in network order), sorted by
+ their corresponding offsets in the packfile.
+</p>
+</li>
+<li>
+<p>
+A trailer, containing a:
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>checksum of the corresponding packfile, and</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>a checksum of all of the above.</code></pre>
+</div></div>
+</li>
+</ul></div>
+<div class="paragraph"><p>All 4-byte numbers are in network order.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_pack_mtimes_files_have_the_format">pack-*.mtimes files have the format:</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>All 4-byte numbers are in network byte order.</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+A 4-byte magic number <em>0x4d544d45</em> (<em>MTME</em>).
+</p>
+</li>
+<li>
+<p>
+A 4-byte version identifier (= 1).
+</p>
+</li>
+<li>
+<p>
+A 4-byte hash function identifier (= 1 for SHA-1, 2 for SHA-256).
+</p>
+</li>
+<li>
+<p>
+A table of 4-byte unsigned integers. The ith value is the
+ modification time (mtime) of the ith object in the corresponding
+ pack by lexicographic (index) order. The mtimes count standard
+ epoch seconds.
+</p>
+</li>
+<li>
+<p>
+A trailer, containing a checksum of the corresponding packfile,
+ and a checksum of all of the above (each having length according
+ to the specified hash function).
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_multi_pack_index_midx_files_have_the_following_format">multi-pack-index (MIDX) files have the following format:</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The multi-pack-index files refer to multiple pack-files and loose objects.</p></div>
+<div class="paragraph"><p>In order to allow extensions that add extra data to the MIDX, we organize
+the body into "chunks" and provide a lookup table at the beginning of the
+body. The header includes certain length values, such as the number of packs,
+the number of base MIDX files, hash lengths and types.</p></div>
+<div class="paragraph"><p>All 4-byte numbers are in network order.</p></div>
+<div class="paragraph"><p>HEADER:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte signature:
+ The signature is: {'M', 'I', 'D', 'X'}</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-byte version number:
+ Git only writes or recognizes version 1.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-byte Object Id Version
+ We infer the length of object IDs (OIDs) from this value:
+ 1 =&gt; SHA-1
+ 2 =&gt; SHA-256
+ If the hash type does not match the repository's hash algorithm,
+ the multi-pack-index file should be ignored with a warning
+ presented to the user.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-byte number of "chunks"</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1-byte number of base multi-pack-index files:
+ This value is currently always zero.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>4-byte number of pack files</code></pre>
+</div></div>
+<div class="paragraph"><p>CHUNK LOOKUP:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>(C + 1) * 12 bytes providing the chunk offsets:
+ First 4 bytes describe chunk id. Value 0 is a terminating label.
+ Other 8 bytes provide offset in current file for chunk to start.
+ (Chunks are provided in file-order, so you can infer the length
+ using the next chunk position if necessary.)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The CHUNK LOOKUP matches the table of contents from
+the chunk-based file format, see linkgit:gitformat-chunk[5].</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>The remaining data in the body is described one chunk at a time, and
+these chunks may be given in any order. Chunks are required unless
+otherwise specified.</code></pre>
+</div></div>
+<div class="paragraph"><p>CHUNK DATA:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Packfile Names (ID: {'P', 'N', 'A', 'M'})
+ Stores the packfile names as concatenated, null-terminated strings.
+ Packfiles must be listed in lexicographic order for fast lookups by
+ name. This is the only chunk not guaranteed to be a multiple of four
+ bytes in length, so should be the last chunk for alignment reasons.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>OID Fanout (ID: {'O', 'I', 'D', 'F'})
+ The ith entry, F[i], stores the number of OIDs with first
+ byte at most i. Thus F[255] stores the total
+ number of objects.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>OID Lookup (ID: {'O', 'I', 'D', 'L'})
+ The OIDs for all objects in the MIDX are stored in lexicographic
+ order in this chunk.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Object Offsets (ID: {'O', 'O', 'F', 'F'})
+ Stores two 4-byte values for every object.
+ 1: The pack-int-id for the pack storing this object.
+ 2: The offset within the pack.
+ If all offsets are less than 2^32, then the large offset chunk
+ will not exist and offsets are stored as in IDX v1.
+ If there is at least one offset value larger than 2^32-1, then
+ the large offset chunk must exist, and offsets larger than
+ 2^31-1 must be stored in it instead. If the large offset chunk
+ exists and the 31st bit is on, then removing that bit reveals
+ the row in the large offsets containing the 8-byte offset of
+ this object.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[Optional] Object Large Offsets (ID: {'L', 'O', 'F', 'F'})
+ 8-byte offsets into large packfiles.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[Optional] Bitmap pack order (ID: {'R', 'I', 'D', 'X'})
+ A list of MIDX positions (one per object in the MIDX, num_objects in
+ total, each a 4-byte unsigned integer in network byte order), sorted
+ according to their relative bitmap/pseudo-pack positions.</code></pre>
+</div></div>
+<div class="paragraph"><p>TRAILER:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>Index checksum of the above contents.</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_multi_pack_index_reverse_indexes">multi-pack-index reverse indexes</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Similar to the pack-based reverse index, the multi-pack index can also
+be used to generate a reverse index.</p></div>
+<div class="paragraph"><p>Instead of mapping between offset, pack-, and index position, this
+reverse index maps between an object&#8217;s position within the MIDX, and
+that object&#8217;s position within a pseudo-pack that the MIDX describes
+(i.e., the ith entry of the multi-pack reverse index holds the MIDX
+position of ith object in pseudo-pack order).</p></div>
+<div class="paragraph"><p>To clarify the difference between these orderings, consider a multi-pack
+reachability bitmap (which does not yet exist, but is what we are
+building towards here). Each bit needs to correspond to an object in the
+MIDX, and so we need an efficient mapping from bit position to MIDX
+position.</p></div>
+<div class="paragraph"><p>One solution is to let bits occupy the same position in the oid-sorted
+index stored by the MIDX. But because oids are effectively random, their
+resulting reachability bitmaps would have no locality, and thus compress
+poorly. (This is the reason that single-pack bitmaps use the pack
+ordering, and not the .idx ordering, for the same purpose.)</p></div>
+<div class="paragraph"><p>So we&#8217;d like to define an ordering for the whole MIDX based around
+pack ordering, which has far better locality (and thus compresses more
+efficiently). We can think of a pseudo-pack created by the concatenation
+of all of the packs in the MIDX. E.g., if we had a MIDX with three packs
+(a, b, c), with 10, 15, and 20 objects respectively, we can imagine an
+ordering of the objects like:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>|a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|</code></pre>
+</div></div>
+<div class="paragraph"><p>where the ordering of the packs is defined by the MIDX&#8217;s pack list,
+and then the ordering of objects within each pack is the same as the
+order in the actual packfile.</p></div>
+<div class="paragraph"><p>Given the list of packs and their counts of objects, you can
+naïvely reconstruct that pseudo-pack ordering (e.g., the object at
+position 27 must be (c,1) because packs "a" and "b" consumed 25 of the
+slots). But there&#8217;s a catch. Objects may be duplicated between packs, in
+which case the MIDX only stores one pointer to the object (and thus we&#8217;d
+want only one slot in the bitmap).</p></div>
+<div class="paragraph"><p>Callers could handle duplicates themselves by reading objects in order
+of their bit-position, but that&#8217;s linear in the number of objects, and
+much too expensive for ordinary bitmap lookups. Building a reverse index
+solves this, since it is the logical inverse of the index, and that
+index has already removed duplicates. But, building a reverse index on
+the fly can be expensive. Since we already have an on-disk format for
+pack-based reverse indexes, let&#8217;s reuse it for the MIDX&#8217;s pseudo-pack,
+too.</p></div>
+<div class="paragraph"><p>Objects from the MIDX are ordered as follows to string together the
+pseudo-pack. Let <code>pack(o)</code> return the pack from which <code>o</code> was selected
+by the MIDX, and define an ordering of packs based on their numeric ID
+(as stored by the MIDX). Let <code>offset(o)</code> return the object offset of <code>o</code>
+within <code>pack(o)</code>. Then, compare <code>o1</code> and <code>o2</code> as follows:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+If one of <code>pack(o1)</code> and <code>pack(o2)</code> is preferred and the other
+ is not, then the preferred one sorts first.
+</p>
+<div class="paragraph"><p>(This is a detail that allows the MIDX bitmap to determine which
+pack should be used by the pack-reuse mechanism, since it can ask
+the MIDX for the pack containing the object at bit position 0).</p></div>
+</li>
+<li>
+<p>
+If <code>pack(o1) ≠ pack(o2)</code>, then sort the two objects in descending
+ order based on the pack ID.
+</p>
+</li>
+<li>
+<p>
+Otherwise, <code>pack(o1) = pack(o2)</code>, and the objects are sorted in
+ pack-order (i.e., <code>o1</code> sorts ahead of <code>o2</code> exactly when <code>offset(o1)
+ &lt; offset(o2)</code>).
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>In short, a MIDX&#8217;s pseudo-pack is the de-duplicated concatenation of
+objects in packs stored by the MIDX, laid out in pack order, and the
+packs arranged in MIDX order (with the preferred pack coming first).</p></div>
+<div class="paragraph"><p>The MIDX&#8217;s reverse index is stored in the optional <em>RIDX</em> chunk within
+the MIDX itself.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_cruft_packs">cruft packs</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The cruft packs feature offer an alternative to Git&#8217;s traditional mechanism of
+removing unreachable objects. This document provides an overview of Git&#8217;s
+pruning mechanism, and how a cruft pack can be used instead to accomplish the
+same.</p></div>
+<div class="sect2">
+<h3 id="_background">Background</h3>
+<div class="paragraph"><p>To remove unreachable objects from your repository, Git offers <code>git repack -Ad</code>
+(see <a href="git-repack.html">git-repack(1)</a>). Quoting from the documentation:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>[...] unreachable objects in a previous pack become loose, unpacked objects,
+instead of being left in the old pack. [...] loose unreachable objects will be
+pruned according to normal expiry rules with the next 'git gc' invocation.</code></pre>
+</div></div>
+<div class="paragraph"><p>Unreachable objects aren&#8217;t removed immediately, since doing so could race with
+an incoming push which may reference an object which is about to be deleted.
+Instead, those unreachable objects are stored as loose objects and stay that way
+until they are older than the expiration window, at which point they are removed
+by <a href="git-prune.html">git-prune(1)</a>.</p></div>
+<div class="paragraph"><p>Git must store these unreachable objects loose in order to keep track of their
+per-object mtimes. If these unreachable objects were written into one big pack,
+then either freshening that pack (because an object contained within it was
+re-written) or creating a new pack of unreachable objects would cause the pack&#8217;s
+mtime to get updated, and the objects within it would never leave the expiration
+window. Instead, objects are stored loose in order to keep track of the
+individual object mtimes and avoid a situation where all cruft objects are
+freshened at once.</p></div>
+<div class="paragraph"><p>This can lead to undesirable situations when a repository contains many
+unreachable objects which have not yet left the grace period. Having large
+directories in the shards of <code>.git/objects</code> can lead to decreased performance in
+the repository. But given enough unreachable objects, this can lead to inode
+starvation and degrade the performance of the whole system. Since we
+can never pack those objects, these repositories often take up a large amount of
+disk space, since we can only zlib compress them, but not store them in delta
+chains.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_cruft_packs_2">Cruft packs</h3>
+<div class="paragraph"><p>A cruft pack eliminates the need for storing unreachable objects in a loose
+state by including the per-object mtimes in a separate file alongside a single
+pack containing all loose objects.</p></div>
+<div class="paragraph"><p>A cruft pack is written by <code>git repack --cruft</code> when generating a new pack.
+<a href="git-pack-objects.html">git-pack-objects(1)</a>'s <code>--cruft</code> option. Note that <code>git repack --cruft</code>
+is a classic all-into-one repack, meaning that everything in the resulting pack is
+reachable, and everything else is unreachable. Once written, the <code>--cruft</code>
+option instructs <code>git repack</code> to generate another pack containing only objects
+not packed in the previous step (which equates to packing all unreachable
+objects together). This progresses as follows:</p></div>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+Enumerate every object, marking any object which is (a) not contained in a
+ kept-pack, and (b) whose mtime is within the grace period as a traversal
+ tip.
+</p>
+</li>
+<li>
+<p>
+Perform a reachability traversal based on the tips gathered in the previous
+ step, adding every object along the way to the pack.
+</p>
+</li>
+<li>
+<p>
+Write the pack out, along with a <code>.mtimes</code> file that records the per-object
+ timestamps.
+</p>
+</li>
+</ol></div>
+<div class="paragraph"><p>This mode is invoked internally by <a href="git-repack.html">git-repack(1)</a> when instructed to
+write a cruft pack. Crucially, the set of in-core kept packs is exactly the set
+of packs which will not be deleted by the repack; in other words, they contain
+all of the repository&#8217;s reachable objects.</p></div>
+<div class="paragraph"><p>When a repository already has a cruft pack, <code>git repack --cruft</code> typically only
+adds objects to it. An exception to this is when <code>git repack</code> is given the
+<code>--cruft-expiration</code> option, which allows the generated cruft pack to omit
+expired objects instead of waiting for <a href="git-gc.html">git-gc(1)</a> to expire those objects
+later on.</p></div>
+<div class="paragraph"><p>It is <a href="git-gc.html">git-gc(1)</a> that is typically responsible for removing expired
+unreachable objects.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_caution_for_mixed_version_environments">Caution for mixed-version environments</h3>
+<div class="paragraph"><p>Repositories that have cruft packs in them will continue to work with any older
+version of Git. Note, however, that previous versions of Git which do not
+understand the <code>.mtimes</code> file will use the cruft pack&#8217;s mtime as the mtime for
+all of the objects in it. In other words, do not expect older (pre-cruft pack)
+versions of Git to interpret or even read the contents of the <code>.mtimes</code> file.</p></div>
+<div class="paragraph"><p>Note that having mixed versions of Git GC-ing the same repository can lead to
+unreachable objects never being completely pruned. This can happen under the
+following circumstances:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+An older version of Git running GC explodes the contents of an existing
+ cruft pack loose, using the cruft pack&#8217;s mtime.
+</p>
+</li>
+<li>
+<p>
+A newer version running GC collects those loose objects into a cruft pack,
+ where the .mtime file reflects the loose object&#8217;s actual mtimes, but the
+ cruft pack mtime is "now".
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Repeating this process will lead to unreachable objects not getting pruned as a
+result of repeatedly resetting the objects' mtimes to the present time.</p></div>
+<div class="paragraph"><p>If you are GC-ing repositories in a mixed version environment, consider omitting
+the <code>--cruft</code> option when using <a href="git-repack.html">git-repack(1)</a> and <a href="git-gc.html">git-gc(1)</a>, and
+leaving the <code>gc.cruftPacks</code> configuration unset until all writers understand
+cruft packs.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_alternatives">Alternatives</h3>
+<div class="paragraph"><p>Notable alternatives to this design include:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+The location of the per-object mtime data, and
+</p>
+</li>
+<li>
+<p>
+Storing unreachable objects in multiple cruft packs.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>On the location of mtime data, a new auxiliary file tied to the pack was chosen
+to avoid complicating the <code>.idx</code> format. If the <code>.idx</code> format were ever to gain
+support for optional chunks of data, it may make sense to consolidate the
+<code>.mtimes</code> format into the <code>.idx</code> itself.</p></div>
+<div class="paragraph"><p>Storing unreachable objects among multiple cruft packs (e.g., creating a new
+cruft pack during each repacking operation including only unreachable objects
+which aren&#8217;t already stored in an earlier cruft pack) is significantly more
+complicated to construct, and so aren&#8217;t pursued here. The obvious drawback to
+the current implementation is that the entire cruft pack must be re-written from
+scratch.</p></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/pack-format.txt b/gitformat-pack.txt
index b520aa9c4..e06af02f2 100644
--- a/technical/pack-format.txt
+++ b/gitformat-pack.txt
@@ -1,5 +1,30 @@
-Git pack format
-===============
+gitformat-pack(5)
+=================
+
+NAME
+----
+gitformat-pack - Git pack format
+
+
+SYNOPSIS
+--------
+[verse]
+$GIT_DIR/objects/pack/pack-*.{pack,idx}
+$GIT_DIR/objects/pack/pack-*.rev
+$GIT_DIR/objects/pack/pack-*.mtimes
+$GIT_DIR/objects/pack/multi-pack-index
+
+DESCRIPTION
+-----------
+
+The Git pack format is now Git stores most of its primary repository
+data. Over the lietime af a repository loose objects (if any) and
+smaller packs are consolidated into larger pack(s). See
+linkgit:git-gc[1] and linkgit:git-pack-objects[1].
+
+The pack format is also used over-the-wire, see
+e.g. linkgit:gitprotocol-v2[5], as well as being a part of
+other container formats in the case of linkgit:gitformat-bundle[5].
== Checksums and object IDs
@@ -356,7 +381,7 @@ CHUNK LOOKUP:
using the next chunk position if necessary.)
The CHUNK LOOKUP matches the table of contents from
- link:technical/chunk-format.html[the chunk-based file format].
+ the chunk-based file format, see linkgit:gitformat-chunk[5].
The remaining data in the body is described one chunk at a time, and
these chunks may be given in any order. Chunks are required unless
@@ -482,3 +507,132 @@ packs arranged in MIDX order (with the preferred pack coming first).
The MIDX's reverse index is stored in the optional 'RIDX' chunk within
the MIDX itself.
+
+== cruft packs
+
+The cruft packs feature offer an alternative to Git's traditional mechanism of
+removing unreachable objects. This document provides an overview of Git's
+pruning mechanism, and how a cruft pack can be used instead to accomplish the
+same.
+
+=== Background
+
+To remove unreachable objects from your repository, Git offers `git repack -Ad`
+(see linkgit:git-repack[1]). Quoting from the documentation:
+
+----
+[...] unreachable objects in a previous pack become loose, unpacked objects,
+instead of being left in the old pack. [...] loose unreachable objects will be
+pruned according to normal expiry rules with the next 'git gc' invocation.
+----
+
+Unreachable objects aren't removed immediately, since doing so could race with
+an incoming push which may reference an object which is about to be deleted.
+Instead, those unreachable objects are stored as loose objects and stay that way
+until they are older than the expiration window, at which point they are removed
+by linkgit:git-prune[1].
+
+Git must store these unreachable objects loose in order to keep track of their
+per-object mtimes. If these unreachable objects were written into one big pack,
+then either freshening that pack (because an object contained within it was
+re-written) or creating a new pack of unreachable objects would cause the pack's
+mtime to get updated, and the objects within it would never leave the expiration
+window. Instead, objects are stored loose in order to keep track of the
+individual object mtimes and avoid a situation where all cruft objects are
+freshened at once.
+
+This can lead to undesirable situations when a repository contains many
+unreachable objects which have not yet left the grace period. Having large
+directories in the shards of `.git/objects` can lead to decreased performance in
+the repository. But given enough unreachable objects, this can lead to inode
+starvation and degrade the performance of the whole system. Since we
+can never pack those objects, these repositories often take up a large amount of
+disk space, since we can only zlib compress them, but not store them in delta
+chains.
+
+=== Cruft packs
+
+A cruft pack eliminates the need for storing unreachable objects in a loose
+state by including the per-object mtimes in a separate file alongside a single
+pack containing all loose objects.
+
+A cruft pack is written by `git repack --cruft` when generating a new pack.
+linkgit:git-pack-objects[1]'s `--cruft` option. Note that `git repack --cruft`
+is a classic all-into-one repack, meaning that everything in the resulting pack is
+reachable, and everything else is unreachable. Once written, the `--cruft`
+option instructs `git repack` to generate another pack containing only objects
+not packed in the previous step (which equates to packing all unreachable
+objects together). This progresses as follows:
+
+ 1. Enumerate every object, marking any object which is (a) not contained in a
+ kept-pack, and (b) whose mtime is within the grace period as a traversal
+ tip.
+
+ 2. Perform a reachability traversal based on the tips gathered in the previous
+ step, adding every object along the way to the pack.
+
+ 3. Write the pack out, along with a `.mtimes` file that records the per-object
+ timestamps.
+
+This mode is invoked internally by linkgit:git-repack[1] when instructed to
+write a cruft pack. Crucially, the set of in-core kept packs is exactly the set
+of packs which will not be deleted by the repack; in other words, they contain
+all of the repository's reachable objects.
+
+When a repository already has a cruft pack, `git repack --cruft` typically only
+adds objects to it. An exception to this is when `git repack` is given the
+`--cruft-expiration` option, which allows the generated cruft pack to omit
+expired objects instead of waiting for linkgit:git-gc[1] to expire those objects
+later on.
+
+It is linkgit:git-gc[1] that is typically responsible for removing expired
+unreachable objects.
+
+=== Caution for mixed-version environments
+
+Repositories that have cruft packs in them will continue to work with any older
+version of Git. Note, however, that previous versions of Git which do not
+understand the `.mtimes` file will use the cruft pack's mtime as the mtime for
+all of the objects in it. In other words, do not expect older (pre-cruft pack)
+versions of Git to interpret or even read the contents of the `.mtimes` file.
+
+Note that having mixed versions of Git GC-ing the same repository can lead to
+unreachable objects never being completely pruned. This can happen under the
+following circumstances:
+
+ - An older version of Git running GC explodes the contents of an existing
+ cruft pack loose, using the cruft pack's mtime.
+ - A newer version running GC collects those loose objects into a cruft pack,
+ where the .mtime file reflects the loose object's actual mtimes, but the
+ cruft pack mtime is "now".
+
+Repeating this process will lead to unreachable objects not getting pruned as a
+result of repeatedly resetting the objects' mtimes to the present time.
+
+If you are GC-ing repositories in a mixed version environment, consider omitting
+the `--cruft` option when using linkgit:git-repack[1] and linkgit:git-gc[1], and
+leaving the `gc.cruftPacks` configuration unset until all writers understand
+cruft packs.
+
+=== Alternatives
+
+Notable alternatives to this design include:
+
+ - The location of the per-object mtime data, and
+ - Storing unreachable objects in multiple cruft packs.
+
+On the location of mtime data, a new auxiliary file tied to the pack was chosen
+to avoid complicating the `.idx` format. If the `.idx` format were ever to gain
+support for optional chunks of data, it may make sense to consolidate the
+`.mtimes` format into the `.idx` itself.
+
+Storing unreachable objects among multiple cruft packs (e.g., creating a new
+cruft pack during each repacking operation including only unreachable objects
+which aren't already stored in an earlier cruft pack) is significantly more
+complicated to construct, and so aren't pursued here. The obvious drawback to
+the current implementation is that the entire cruft pack must be re-written from
+scratch.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitformat-signature.html b/gitformat-signature.html
new file mode 100644
index 000000000..27d7e5650
--- /dev/null
+++ b/gitformat-signature.html
@@ -0,0 +1,1042 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitformat-signature(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitformat-signature(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitformat-signature -
+ Git cryptographic signature formats
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">&lt;[tag|commit] object header(s)&gt;
+&lt;over-the-wire protocol&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Git uses cryptographic signatures in various places, currently objects (tags,
+commits, mergetags) and transactions (pushes). In every case, the command which
+is about to create an object or transaction determines a payload from that,
+calls gpg to obtain a detached signature for the payload (<code>gpg -bsa</code>) and
+embeds the signature into the object or transaction.</p></div>
+<div class="paragraph"><p>Signatures always begin with <code>-----BEGIN PGP SIGNATURE-----</code>
+and end with <code>-----END PGP SIGNATURE-----</code>, unless gpg is told to
+produce RFC1991 signatures which use <code>MESSAGE</code> instead of <code>SIGNATURE</code>.</p></div>
+<div class="paragraph"><p>Signatures sometimes appear as a part of the normal payload
+(e.g. a signed tag has the signature block appended after the payload
+that the signature applies to), and sometimes appear in the value of
+an object header (e.g. a merge commit that merged a signed tag would
+have the entire tag contents on its "mergetag" header). In the case
+of the latter, the usual multi-line formatting rule for object
+headers applies. I.e. the second and subsequent lines are prefixed
+with a SP to signal that the line is continued from the previous
+line.</p></div>
+<div class="paragraph"><p>This is even true for an originally empty line. In the following
+examples, the end of line that ends with a whitespace letter is
+highlighted with a <code>$</code> sign; if you are trying to recreate these
+example by hand, do not cut and paste them---they are there
+primarily to highlight extra whitespace at the end of some lines.</p></div>
+<div class="paragraph"><p>The signed payload and the way the signature is embedded depends
+on the type of the object resp. transaction.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_tag_signatures">Tag signatures</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+created by: <code>git tag -s</code>
+</p>
+</li>
+<li>
+<p>
+payload: annotated tag object
+</p>
+</li>
+<li>
+<p>
+embedding: append the signature to the unsigned tag object
+</p>
+</li>
+<li>
+<p>
+example: tag <code>signedtag</code> with subject <code>signed tag</code>
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>object 04b871796dc0420f8e7561a895b52484b701d51a
+type commit
+tag signedtag
+tagger C O Mitter &lt;committer@example.com&gt; 1465981006 +0000
+
+signed tag
+
+signed tag message body
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQEcBAABAgAGBQJXYRhOAAoJEGEJLoW3InGJklkIAIcnhL7RwEb/+QeX9enkXhxn
+rxfdqrvWd1K80sl2TOt8Bg/NYwrUBw/RWJ+sg/hhHp4WtvE1HDGHlkEz3y11Lkuh
+8tSxS3qKTxXUGozyPGuE90sJfExhZlW4knIQ1wt/yWqM+33E9pN4hzPqLwyrdods
+q8FWEqPPUbSJXoMbRPw04S5jrLtZSsUWbRYjmJCHzlhSfFWW4eFd37uquIaLUBS0
+rkC3Jrx7420jkIpgFcTI2s60uhSQLzgcCwdA2ukSYIRnjg/zDkj8+3h/GaROJ72x
+lZyI6HWixKJkWw8lE9aAOD9TmTW9sFJwcVAzmAuFX2kUreDUKMZduGcoRYGpD7E=
+=jpXa
+-----END PGP SIGNATURE-----</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+verify with: <code>git verify-tag [-v]</code> or <code>git tag -v</code>
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>gpg: Signature made Wed Jun 15 10:56:46 2016 CEST using RSA key ID B7227189
+gpg: Good signature from "Eris Discordia &lt;discord@example.net&gt;"
+gpg: WARNING: This key is not certified with a trusted signature!
+gpg: There is no indication that the signature belongs to the owner.
+Primary key fingerprint: D4BE 2231 1AD3 131E 5EDA 29A4 6109 2E85 B722 7189
+object 04b871796dc0420f8e7561a895b52484b701d51a
+type commit
+tag signedtag
+tagger C O Mitter &lt;committer@example.com&gt; 1465981006 +0000
+
+signed tag
+
+signed tag message body</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_commit_signatures">Commit signatures</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+created by: <code>git commit -S</code>
+</p>
+</li>
+<li>
+<p>
+payload: commit object
+</p>
+</li>
+<li>
+<p>
+embedding: header entry <code>gpgsig</code>
+ (content is preceded by a space)
+</p>
+</li>
+<li>
+<p>
+example: commit with subject <code>signed commit</code>
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>tree eebfed94e75e7760540d1485c740902590a00332
+parent 04b871796dc0420f8e7561a895b52484b701d51a
+author A U Thor &lt;author@example.com&gt; 1465981137 +0000
+committer C O Mitter &lt;committer@example.com&gt; 1465981137 +0000
+gpgsig -----BEGIN PGP SIGNATURE-----
+ Version: GnuPG v1
+ $
+ iQEcBAABAgAGBQJXYRjRAAoJEGEJLoW3InGJ3IwIAIY4SA6GxY3BjL60YyvsJPh/
+ HRCJwH+w7wt3Yc/9/bW2F+gF72kdHOOs2jfv+OZhq0q4OAN6fvVSczISY/82LpS7
+ DVdMQj2/YcHDT4xrDNBnXnviDO9G7am/9OE77kEbXrp7QPxvhjkicHNwy2rEflAA
+ zn075rtEERDHr8nRYiDh8eVrefSO7D+bdQ7gv+7GsYMsd2auJWi1dHOSfTr9HIF4
+ HJhWXT9d2f8W+diRYXGh4X0wYiGg6na/soXc+vdtDYBzIxanRqjg8jCAeo1eOTk1
+ EdTwhcTZlI0x5pvJ3H0+4hA2jtldVtmPM4OTB0cTrEWBad7XV6YgiyuII73Ve3I=
+ =jKHM
+ -----END PGP SIGNATURE-----
+
+signed commit
+
+signed commit message body</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+verify with: <code>git verify-commit [-v]</code> (or <code>git show --show-signature</code>)
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>gpg: Signature made Wed Jun 15 10:58:57 2016 CEST using RSA key ID B7227189
+gpg: Good signature from "Eris Discordia &lt;discord@example.net&gt;"
+gpg: WARNING: This key is not certified with a trusted signature!
+gpg: There is no indication that the signature belongs to the owner.
+Primary key fingerprint: D4BE 2231 1AD3 131E 5EDA 29A4 6109 2E85 B722 7189
+tree eebfed94e75e7760540d1485c740902590a00332
+parent 04b871796dc0420f8e7561a895b52484b701d51a
+author A U Thor &lt;author@example.com&gt; 1465981137 +0000
+committer C O Mitter &lt;committer@example.com&gt; 1465981137 +0000
+
+signed commit
+
+signed commit message body</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_mergetag_signatures">Mergetag signatures</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+created by: <code>git merge</code> on signed tag
+</p>
+</li>
+<li>
+<p>
+payload/embedding: the whole signed tag object is embedded into
+ the (merge) commit object as header entry <code>mergetag</code>
+</p>
+</li>
+<li>
+<p>
+example: merge of the signed tag <code>signedtag</code> as above
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>tree c7b1cff039a93f3600a1d18b82d26688668c7dea
+parent c33429be94b5f2d3ee9b0adad223f877f174b05d
+parent 04b871796dc0420f8e7561a895b52484b701d51a
+author A U Thor &lt;author@example.com&gt; 1465982009 +0000
+committer C O Mitter &lt;committer@example.com&gt; 1465982009 +0000
+mergetag object 04b871796dc0420f8e7561a895b52484b701d51a
+ type commit
+ tag signedtag
+ tagger C O Mitter &lt;committer@example.com&gt; 1465981006 +0000
+ $
+ signed tag
+ $
+ signed tag message body
+ -----BEGIN PGP SIGNATURE-----
+ Version: GnuPG v1
+ $
+ iQEcBAABAgAGBQJXYRhOAAoJEGEJLoW3InGJklkIAIcnhL7RwEb/+QeX9enkXhxn
+ rxfdqrvWd1K80sl2TOt8Bg/NYwrUBw/RWJ+sg/hhHp4WtvE1HDGHlkEz3y11Lkuh
+ 8tSxS3qKTxXUGozyPGuE90sJfExhZlW4knIQ1wt/yWqM+33E9pN4hzPqLwyrdods
+ q8FWEqPPUbSJXoMbRPw04S5jrLtZSsUWbRYjmJCHzlhSfFWW4eFd37uquIaLUBS0
+ rkC3Jrx7420jkIpgFcTI2s60uhSQLzgcCwdA2ukSYIRnjg/zDkj8+3h/GaROJ72x
+ lZyI6HWixKJkWw8lE9aAOD9TmTW9sFJwcVAzmAuFX2kUreDUKMZduGcoRYGpD7E=
+ =jpXa
+ -----END PGP SIGNATURE-----
+
+Merge tag 'signedtag' into downstream
+
+signed tag
+
+signed tag message body
+
+# gpg: Signature made Wed Jun 15 08:56:46 2016 UTC using RSA key ID B7227189
+# gpg: Good signature from "Eris Discordia &lt;discord@example.net&gt;"
+# gpg: WARNING: This key is not certified with a trusted signature!
+# gpg: There is no indication that the signature belongs to the owner.
+# Primary key fingerprint: D4BE 2231 1AD3 131E 5EDA 29A4 6109 2E85 B722 7189</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+verify with: verification is embedded in merge commit message by default,
+ alternatively with <code>git show --show-signature</code>:
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>commit 9863f0c76ff78712b6800e199a46aa56afbcbd49
+merged tag 'signedtag'
+gpg: Signature made Wed Jun 15 10:56:46 2016 CEST using RSA key ID B7227189
+gpg: Good signature from "Eris Discordia &lt;discord@example.net&gt;"
+gpg: WARNING: This key is not certified with a trusted signature!
+gpg: There is no indication that the signature belongs to the owner.
+Primary key fingerprint: D4BE 2231 1AD3 131E 5EDA 29A4 6109 2E85 B722 7189
+Merge: c33429b 04b8717
+Author: A U Thor &lt;author@example.com&gt;
+Date: Wed Jun 15 09:13:29 2016 +0000
+
+ Merge tag 'signedtag' into downstream
+
+ signed tag
+
+ signed tag message body
+
+ # gpg: Signature made Wed Jun 15 08:56:46 2016 UTC using RSA key ID B7227189
+ # gpg: Good signature from "Eris Discordia &lt;discord@example.net&gt;"
+ # gpg: WARNING: This key is not certified with a trusted signature!
+ # gpg: There is no indication that the signature belongs to the owner.
+ # Primary key fingerprint: D4BE 2231 1AD3 131E 5EDA 29A4 6109 2E85 B722 7189</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/signature-format.txt b/gitformat-signature.txt
index 166721be6..a249869fa 100644
--- a/technical/signature-format.txt
+++ b/gitformat-signature.txt
@@ -1,7 +1,18 @@
-Git signature format
-====================
+gitformat-signature(5)
+======================
-== Overview
+NAME
+----
+gitformat-signature - Git cryptographic signature formats
+
+SYNOPSIS
+--------
+[verse]
+<[tag|commit] object header(s)>
+<over-the-wire protocol>
+
+DESCRIPTION
+-----------
Git uses cryptographic signatures in various places, currently objects (tags,
commits, mergetags) and transactions (pushes). In every case, the command which
@@ -200,3 +211,7 @@ Date: Wed Jun 15 09:13:29 2016 +0000
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: D4BE 2231 1AD3 131E 5EDA 29A4 6109 2E85 B722 7189
----
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitprotocol-capabilities.html b/gitprotocol-capabilities.html
new file mode 100644
index 000000000..925a43b77
--- /dev/null
+++ b/gitprotocol-capabilities.html
@@ -0,0 +1,1161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitprotocol-capabilities(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitprotocol-capabilities(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitprotocol-capabilities -
+ Protocol v0 and v1 capabilities
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">&lt;over-the-wire-protocol&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="admonitionblock">
+<table><tr>
+<td class="icon">
+<div class="title">Note</div>
+</td>
+<td class="content">this document describes capabilities for versions 0 and 1 of the pack
+protocol. For version 2, please refer to the <a href="gitprotocol-v2.html">gitprotocol-v2(5)</a>
+doc.</td>
+</tr></table>
+</div>
+<div class="paragraph"><p>Servers SHOULD support all capabilities defined in this document.</p></div>
+<div class="paragraph"><p>On the very first line of the initial server response of either
+receive-pack and upload-pack the first reference is followed by
+a NUL byte and then a list of space delimited server capabilities.
+These allow the server to declare what it can and cannot support
+to the client.</p></div>
+<div class="paragraph"><p>Client will then send a space separated list of capabilities it wants
+to be in effect. The client MUST NOT ask for capabilities the server
+did not say it supports.</p></div>
+<div class="paragraph"><p>Server MUST diagnose and abort if capabilities it does not understand
+was sent. Server MUST NOT ignore capabilities that client requested
+and server advertised. As a consequence of these rules, server MUST
+NOT advertise capabilities it does not understand.</p></div>
+<div class="paragraph"><p>The <em>atomic</em>, <em>report-status</em>, <em>report-status-v2</em>, <em>delete-refs</em>, <em>quiet</em>,
+and <em>push-cert</em> capabilities are sent and recognized by the receive-pack
+(push to server) process.</p></div>
+<div class="paragraph"><p>The <em>ofs-delta</em> and <em>side-band-64k</em> capabilities are sent and recognized
+by both upload-pack and receive-pack protocols. The <em>agent</em> and <em>session-id</em>
+capabilities may optionally be sent in both protocols.</p></div>
+<div class="paragraph"><p>All other capabilities are only recognized by the upload-pack (fetch
+from server) process.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_multi_ack">multi_ack</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The <em>multi_ack</em> capability allows the server to return "ACK obj-id
+continue" as soon as it finds a commit that it can use as a common
+base, between the client&#8217;s wants and the client&#8217;s have set.</p></div>
+<div class="paragraph"><p>By sending this early, the server can potentially head off the client
+from walking any further down that particular branch of the client&#8217;s
+repository history. The client may still need to walk down other
+branches, sending have lines for those, until the server has a
+complete cut across the DAG, or the client has said "done".</p></div>
+<div class="paragraph"><p>Without multi_ack, a client sends have lines in --date-order until
+the server has found a common base. That means the client will send
+have lines that are already known by the server to be common, because
+they overlap in time with another branch that the server hasn&#8217;t found
+a common base on yet.</p></div>
+<div class="paragraph"><p>For example suppose the client has commits in caps that the server
+doesn&#8217;t and the server has commits in lower case that the client
+doesn&#8217;t, as in the following diagram:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code> +---- u ---------------------- x
+ / +----- y
+ / /
+a -- b -- c -- d -- E -- F
+ \
+ +--- Q -- R -- S</code></pre>
+</div></div>
+<div class="paragraph"><p>If the client wants x,y and starts out by saying have F,S, the server
+doesn&#8217;t know what F,S is. Eventually the client says "have d" and
+the server sends "ACK d continue" to let the client know to stop
+walking down that line (so don&#8217;t send c-b-a), but it&#8217;s not done yet,
+it needs a base for x. The client keeps going with S-R-Q, until a
+gets reached, at which point the server has a clear base and it all
+ends.</p></div>
+<div class="paragraph"><p>Without multi_ack the client would have sent that c-b-a chain anyway,
+interleaved with S-R-Q.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_multi_ack_detailed">multi_ack_detailed</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This is an extension of multi_ack that permits client to better
+understand the server&#8217;s in-memory state. See <a href="gitprotocol-pack.html">gitprotocol-pack(5)</a>,
+section "Packfile Negotiation" for more information.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_no_done">no-done</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This capability should only be used with the smart HTTP protocol. If
+multi_ack_detailed and no-done are both present, then the sender is
+free to immediately send a pack following its first "ACK obj-id ready"
+message.</p></div>
+<div class="paragraph"><p>Without no-done in the smart HTTP protocol, the server session would
+end and the client has to make another trip to send "done" before
+the server can send the pack. no-done removes the last round and
+thus slightly reduces latency.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_thin_pack">thin-pack</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>A thin pack is one with deltas which reference base objects not
+contained within the pack (but are known to exist at the receiving
+end). This can reduce the network traffic significantly, but it
+requires the receiving end to know how to "thicken" these packs by
+adding the missing bases to the pack.</p></div>
+<div class="paragraph"><p>The upload-pack server advertises <em>thin-pack</em> when it can generate
+and send a thin pack. A client requests the <em>thin-pack</em> capability
+when it understands how to "thicken" it, notifying the server that
+it can receive such a pack. A client MUST NOT request the
+<em>thin-pack</em> capability if it cannot turn a thin pack into a
+self-contained pack.</p></div>
+<div class="paragraph"><p>Receive-pack, on the other hand, is assumed by default to be able to
+handle thin packs, but can ask the client not to use the feature by
+advertising the <em>no-thin</em> capability. A client MUST NOT send a thin
+pack if the server advertises the <em>no-thin</em> capability.</p></div>
+<div class="paragraph"><p>The reasons for this asymmetry are historical. The receive-pack
+program did not exist until after the invention of thin packs, so
+historically the reference implementation of receive-pack always
+understood thin packs. Adding <em>no-thin</em> later allowed receive-pack
+to disable the feature in a backwards-compatible manner.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_side_band_side_band_64k">side-band, side-band-64k</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This capability means that server can send, and client understand multiplexed
+progress reports and error info interleaved with the packfile itself.</p></div>
+<div class="paragraph"><p>These two options are mutually exclusive. A modern client always
+favors <em>side-band-64k</em>.</p></div>
+<div class="paragraph"><p>Either mode indicates that the packfile data will be streamed broken
+up into packets of up to either 1000 bytes in the case of <em>side_band</em>,
+or 65520 bytes in the case of <em>side_band_64k</em>. Each packet is made up
+of a leading 4-byte pkt-line length of how much data is in the packet,
+followed by a 1-byte stream code, followed by the actual data.</p></div>
+<div class="paragraph"><p>The stream code can be one of:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>1 - pack data
+2 - progress messages
+3 - fatal error message just before stream aborts</code></pre>
+</div></div>
+<div class="paragraph"><p>The "side-band-64k" capability came about as a way for newer clients
+that can handle much larger packets to request packets that are
+actually crammed nearly full, while maintaining backward compatibility
+for the older clients.</p></div>
+<div class="paragraph"><p>Further, with side-band and its up to 1000-byte messages, it&#8217;s actually
+999 bytes of payload and 1 byte for the stream code. With side-band-64k,
+same deal, you have up to 65519 bytes of data and 1 byte for the stream
+code.</p></div>
+<div class="paragraph"><p>The client MUST send only maximum of one of "side-band" and "side-
+band-64k". Server MUST diagnose it as an error if client requests
+both.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ofs_delta">ofs-delta</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Server can send, and client understand PACKv2 with delta referring to
+its base by position in pack rather than by an obj-id. That is, they can
+send/read OBJ_OFS_DELTA (aka type 6) in a packfile.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_agent">agent</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The server may optionally send a capability of the form <code>agent=X</code> to
+notify the client that the server is running version <code>X</code>. The client may
+optionally return its own agent string by responding with an <code>agent=Y</code>
+capability (but it MUST NOT do so if the server did not mention the
+agent capability). The <code>X</code> and <code>Y</code> strings may contain any printable
+ASCII characters except space (i.e., the byte range 32 &lt; x &lt; 127), and
+are typically of the form "package/version" (e.g., "git/1.8.3.1"). The
+agent strings are purely informative for statistics and debugging
+purposes, and MUST NOT be used to programmatically assume the presence
+or absence of particular features.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_object_format">object-format</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This capability, which takes a hash algorithm as an argument, indicates
+that the server supports the given hash algorithms. It may be sent
+multiple times; if so, the first one given is the one used in the ref
+advertisement.</p></div>
+<div class="paragraph"><p>When provided by the client, this indicates that it intends to use the
+given hash algorithm to communicate. The algorithm provided must be one
+that the server supports.</p></div>
+<div class="paragraph"><p>If this capability is not provided, it is assumed that the only
+supported algorithm is SHA-1.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_symref">symref</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This parameterized capability is used to inform the receiver which symbolic ref
+points to which ref; for example, "symref=HEAD:refs/heads/master" tells the
+receiver that HEAD points to master. This capability can be repeated to
+represent multiple symrefs.</p></div>
+<div class="paragraph"><p>Servers SHOULD include this capability for the HEAD symref if it is one of the
+refs being sent.</p></div>
+<div class="paragraph"><p>Clients MAY use the parameters from this capability to select the proper initial
+branch when cloning a repository.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_shallow">shallow</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This capability adds "deepen", "shallow" and "unshallow" commands to
+the fetch-pack/upload-pack protocol so clients can request shallow
+clones.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_deepen_since">deepen-since</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This capability adds "deepen-since" command to fetch-pack/upload-pack
+protocol so the client can request shallow clones that are cut at a
+specific time, instead of depth. Internally it&#8217;s equivalent of doing
+"rev-list --max-age=&lt;timestamp&gt;" on the server side. "deepen-since"
+cannot be used with "deepen".</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_deepen_not">deepen-not</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This capability adds "deepen-not" command to fetch-pack/upload-pack
+protocol so the client can request shallow clones that are cut at a
+specific revision, instead of depth. Internally it&#8217;s equivalent of
+doing "rev-list --not &lt;rev&gt;" on the server side. "deepen-not"
+cannot be used with "deepen", but can be used with "deepen-since".</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_deepen_relative">deepen-relative</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If this capability is requested by the client, the semantics of
+"deepen" command is changed. The "depth" argument is the depth from
+the current shallow boundary, instead of the depth from remote refs.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_no_progress">no-progress</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The client was started with "git clone -q" or something, and doesn&#8217;t
+want that side band 2. Basically the client just says "I do not
+wish to receive stream 2 on sideband, so do not send it to me, and if
+you did, I will drop it on the floor anyway". However, the sideband
+channel 3 is still used for error responses.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_include_tag">include-tag</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The <em>include-tag</em> capability is about sending annotated tags if we are
+sending objects they point to. If we pack an object to the client, and
+a tag object points exactly at that object, we pack the tag object too.
+In general this allows a client to get all new annotated tags when it
+fetches a branch, in a single network connection.</p></div>
+<div class="paragraph"><p>Clients MAY always send include-tag, hardcoding it into a request when
+the server advertises this capability. The decision for a client to
+request include-tag only has to do with the client&#8217;s desires for tag
+data, whether or not a server had advertised objects in the
+refs/tags/* namespace.</p></div>
+<div class="paragraph"><p>Servers MUST pack the tags if their referrant is packed and the client
+has requested include-tags.</p></div>
+<div class="paragraph"><p>Clients MUST be prepared for the case where a server has ignored
+include-tag and has not actually sent tags in the pack. In such
+cases the client SHOULD issue a subsequent fetch to acquire the tags
+that include-tag would have otherwise given the client.</p></div>
+<div class="paragraph"><p>The server SHOULD send include-tag, if it supports it, regardless
+of whether or not there are tags available.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_report_status">report-status</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The receive-pack process can receive a <em>report-status</em> capability,
+which tells it that the client wants a report of what happened after
+a packfile upload and reference update. If the pushing client requests
+this capability, after unpacking and updating references the server
+will respond with whether the packfile unpacked successfully and if
+each reference was updated successfully. If any of those were not
+successful, it will send back an error message. See <a href="gitprotocol-pack.html">gitprotocol-pack(5)</a>
+for example messages.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_report_status_v2">report-status-v2</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Capability <em>report-status-v2</em> extends capability <em>report-status</em> by
+adding new "option" directives in order to support reference rewritten by
+the "proc-receive" hook. The "proc-receive" hook may handle a command
+for a pseudo-reference which may create or update a reference with
+different name, new-oid, and old-oid. While the capability
+<em>report-status</em> cannot report for such case. See <a href="gitprotocol-pack.html">gitprotocol-pack(5)</a>
+for details.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_delete_refs">delete-refs</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If the server sends back the <em>delete-refs</em> capability, it means that
+it is capable of accepting a zero-id value as the target
+value of a reference update. It is not sent back by the client, it
+simply informs the client that it can be sent zero-id values
+to delete references.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_quiet">quiet</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If the receive-pack server advertises the <em>quiet</em> capability, it is
+capable of silencing human-readable progress output which otherwise may
+be shown when processing the received pack. A send-pack client should
+respond with the <em>quiet</em> capability to suppress server-side progress
+reporting if the local progress reporting is also being suppressed
+(e.g., via <code>push -q</code>, or if stderr does not go to a tty).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_atomic">atomic</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If the server sends the <em>atomic</em> capability it is capable of accepting
+atomic pushes. If the pushing client requests this capability, the server
+will update the refs in one atomic transaction. Either all refs are
+updated or none.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_push_options">push-options</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If the server sends the <em>push-options</em> capability it is able to accept
+push options after the update commands have been sent, but before the
+packfile is streamed. If the pushing client requests this capability,
+the server will pass the options to the pre- and post- receive hooks
+that process this push request.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_allow_tip_sha1_in_want">allow-tip-sha1-in-want</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If the upload-pack server advertises this capability, fetch-pack may
+send "want" lines with object names that exist at the server but are not
+advertised by upload-pack. For historical reasons, the name of this
+capability contains "sha1". Object names are always given using the
+object format negotiated through the <em>object-format</em> capability.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_allow_reachable_sha1_in_want">allow-reachable-sha1-in-want</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If the upload-pack server advertises this capability, fetch-pack may
+send "want" lines with object names that exist at the server but are not
+advertised by upload-pack. For historical reasons, the name of this
+capability contains "sha1". Object names are always given using the
+object format negotiated through the <em>object-format</em> capability.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_push_cert_lt_nonce_gt">push-cert=&lt;nonce&gt;</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The receive-pack server that advertises this capability is willing
+to accept a signed push certificate, and asks the &lt;nonce&gt; to be
+included in the push certificate. A send-pack client MUST NOT
+send a push-cert packet unless the receive-pack server advertises
+this capability.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_filter">filter</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If the upload-pack server advertises the <em>filter</em> capability,
+fetch-pack may send "filter" commands to request a partial clone
+or partial fetch and request that the server omit various objects
+from the packfile.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_session_id_lt_session_id_gt">session-id=&lt;session id&gt;</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The server may advertise a session ID that can be used to identify this process
+across multiple requests. The client may advertise its own session ID back to
+the server as well.</p></div>
+<div class="paragraph"><p>Session IDs should be unique to a given process. They must fit within a
+packet-line, and must not contain non-printable or whitespace characters. The
+current implementation uses trace2 session IDs (see
+<a href="api-trace2.html">api-trace2</a> for details), but this may change and users of
+the session ID should not rely on this fact.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/protocol-capabilities.txt b/gitprotocol-capabilities.txt
index 9dfade930..c6dcc7d56 100644
--- a/technical/protocol-capabilities.txt
+++ b/gitprotocol-capabilities.txt
@@ -1,8 +1,20 @@
-Git Protocol Capabilities
-=========================
+gitprotocol-capabilities(5)
+===========================
+
+NAME
+----
+gitprotocol-capabilities - Protocol v0 and v1 capabilities
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
NOTE: this document describes capabilities for versions 0 and 1 of the pack
-protocol. For version 2, please refer to the link:protocol-v2.html[protocol-v2]
+protocol. For version 2, please refer to the linkgit:gitprotocol-v2[5]
doc.
Servers SHOULD support all capabilities defined in this document.
@@ -77,7 +89,7 @@ interleaved with S-R-Q.
multi_ack_detailed
------------------
This is an extension of multi_ack that permits client to better
-understand the server's in-memory state. See pack-protocol.txt,
+understand the server's in-memory state. See linkgit:gitprotocol-pack[5],
section "Packfile Negotiation" for more information.
no-done
@@ -281,7 +293,7 @@ a packfile upload and reference update. If the pushing client requests
this capability, after unpacking and updating references the server
will respond with whether the packfile unpacked successfully and if
each reference was updated successfully. If any of those were not
-successful, it will send back an error message. See pack-protocol.txt
+successful, it will send back an error message. See linkgit:gitprotocol-pack[5]
for example messages.
report-status-v2
@@ -292,7 +304,7 @@ adding new "option" directives in order to support reference rewritten by
the "proc-receive" hook. The "proc-receive" hook may handle a command
for a pseudo-reference which may create or update a reference with
different name, new-oid, and old-oid. While the capability
-'report-status' cannot report for such case. See pack-protocol.txt
+'report-status' cannot report for such case. See linkgit:gitprotocol-pack[5]
for details.
delete-refs
@@ -378,3 +390,7 @@ packet-line, and must not contain non-printable or whitespace characters. The
current implementation uses trace2 session IDs (see
link:api-trace2.html[api-trace2] for details), but this may change and users of
the session ID should not rely on this fact.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitprotocol-common.html b/gitprotocol-common.html
new file mode 100644
index 000000000..3bfaab6a9
--- /dev/null
+++ b/gitprotocol-common.html
@@ -0,0 +1,896 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitprotocol-common(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitprotocol-common(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitprotocol-common -
+ Things common to various protocols
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">&lt;over-the-wire-protocol&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This document sets defines things common to various over-the-wire
+protocols and file formats used in Git.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_abnf_notation">ABNF Notation</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>ABNF notation as described by RFC 5234 is used within the protocol documents,
+except the following replacement core rules are used:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> HEXDIG = DIGIT / "a" / "b" / "c" / "d" / "e" / "f"</code></pre>
+</div></div>
+<div class="paragraph"><p>We also define the following common rules:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> NUL = %x00
+ zero-id = 40*"0"
+ obj-id = 40*(HEXDIGIT)
+
+ refname = "HEAD"
+ refname /= "refs/" &lt;see discussion below&gt;</code></pre>
+</div></div>
+<div class="paragraph"><p>A refname is a hierarchical octet string beginning with "refs/" and
+not violating the <em>git-check-ref-format</em> command&#8217;s validation rules.
+More specifically, they:</p></div>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+They can include slash <code>/</code> for hierarchical (directory)
+ grouping, but no slash-separated component can begin with a
+ dot <code>.</code>.
+</p>
+</li>
+<li>
+<p>
+They must contain at least one <code>/</code>. This enforces the presence of a
+ category like <code>heads/</code>, <code>tags/</code> etc. but the actual names are not
+ restricted.
+</p>
+</li>
+<li>
+<p>
+They cannot have two consecutive dots <code>..</code> anywhere.
+</p>
+</li>
+<li>
+<p>
+They cannot have ASCII control characters (i.e. bytes whose
+ values are lower than \040, or \177 <code>DEL</code>), space, tilde <code>~</code>,
+ caret <code>^</code>, colon <code>:</code>, question-mark <code>?</code>, asterisk <code>*</code>,
+ or open bracket <code>[</code> anywhere.
+</p>
+</li>
+<li>
+<p>
+They cannot end with a slash <code>/</code> or a dot <code>.</code>.
+</p>
+</li>
+<li>
+<p>
+They cannot end with the sequence <code>.lock</code>.
+</p>
+</li>
+<li>
+<p>
+They cannot contain a sequence <code>@{</code>.
+</p>
+</li>
+<li>
+<p>
+They cannot contain a <code>\\</code>.
+</p>
+</li>
+</ol></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_pkt_line_format">pkt-line Format</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Much (but not all) of the payload is described around pkt-lines.</p></div>
+<div class="paragraph"><p>A pkt-line is a variable length binary string. The first four bytes
+of the line, the pkt-len, indicates the total length of the line,
+in hexadecimal. The pkt-len includes the 4 bytes used to contain
+the length&#8217;s hexadecimal representation.</p></div>
+<div class="paragraph"><p>A pkt-line MAY contain binary data, so implementors MUST ensure
+pkt-line parsing/formatting routines are 8-bit clean.</p></div>
+<div class="paragraph"><p>A non-binary line SHOULD BE terminated by an LF, which if present
+MUST be included in the total length. Receivers MUST treat pkt-lines
+with non-binary data the same whether or not they contain the trailing
+LF (stripping the LF if present, and not complaining when it is
+missing).</p></div>
+<div class="paragraph"><p>The maximum length of a pkt-line&#8217;s data component is 65516 bytes.
+Implementations MUST NOT send pkt-line whose length exceeds 65520
+(65516 bytes of payload + 4 bytes of length data).</p></div>
+<div class="paragraph"><p>Implementations SHOULD NOT send an empty pkt-line ("0004").</p></div>
+<div class="paragraph"><p>A pkt-line with a length field of 0 ("0000"), called a flush-pkt,
+is a special case and MUST be handled differently than an empty
+pkt-line ("0004").</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> pkt-line = data-pkt / flush-pkt
+
+ data-pkt = pkt-len pkt-payload
+ pkt-len = 4*(HEXDIG)
+ pkt-payload = (pkt-len - 4)*(OCTET)
+
+ flush-pkt = "0000"</code></pre>
+</div></div>
+<div class="paragraph"><p>Examples (as C-style strings):</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> pkt-line actual value
+ ---------------------------------
+ "0006a\n" "a\n"
+ "0005a" "a"
+ "000bfoobar\n" "foobar\n"
+ "0004" ""</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/protocol-common.txt b/gitprotocol-common.txt
index ecedb34bb..1486651bd 100644
--- a/technical/protocol-common.txt
+++ b/gitprotocol-common.txt
@@ -1,5 +1,20 @@
-Documentation Common to Pack and Http Protocols
-===============================================
+gitprotocol-common(5)
+=====================
+
+NAME
+----
+gitprotocol-common - Things common to various protocols
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
+
+This document sets defines things common to various over-the-wire
+protocols and file formats used in Git.
ABNF Notation
-------------
@@ -97,3 +112,7 @@ Examples (as C-style strings):
"000bfoobar\n" "foobar\n"
"0004" ""
----
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitprotocol-http.html b/gitprotocol-http.html
new file mode 100644
index 000000000..62f55c8f2
--- /dev/null
+++ b/gitprotocol-http.html
@@ -0,0 +1,1286 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitprotocol-http(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitprotocol-http(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitprotocol-http -
+ Git HTTP-based protocols
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">&lt;over-the-wire-protocol&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Git supports two HTTP based transfer protocols. A "dumb" protocol
+which requires only a standard HTTP server on the server end of the
+connection, and a "smart" protocol which requires a Git aware CGI
+(or server module). This document describes both protocols.</p></div>
+<div class="paragraph"><p>As a design feature smart clients can automatically upgrade "dumb"
+protocol URLs to smart URLs. This permits all users to have the
+same published URL, and the peers automatically select the most
+efficient transport available to them.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_url_format">URL Format</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>URLs for Git repositories accessed by HTTP use the standard HTTP
+URL syntax documented by RFC 1738, so they are of the form:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>http://&lt;host&gt;:&lt;port&gt;/&lt;path&gt;?&lt;searchpart&gt;</code></pre>
+</div></div>
+<div class="paragraph"><p>Within this documentation the placeholder <code>$GIT_URL</code> will stand for
+the http:// repository URL entered by the end-user.</p></div>
+<div class="paragraph"><p>Servers SHOULD handle all requests to locations matching <code>$GIT_URL</code>, as
+both the "smart" and "dumb" HTTP protocols used by Git operate
+by appending additional path components onto the end of the user
+supplied <code>$GIT_URL</code> string.</p></div>
+<div class="paragraph"><p>An example of a dumb client requesting for a loose object:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>$GIT_URL: http://example.com:8080/git/repo.git
+URL request: http://example.com:8080/git/repo.git/objects/d0/49f6c27a2244e12041955e262a404c7faba355</code></pre>
+</div></div>
+<div class="paragraph"><p>An example of a smart request to a catch-all gateway:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>$GIT_URL: http://example.com/daemon.cgi?svc=git&amp;q=
+URL request: http://example.com/daemon.cgi?svc=git&amp;q=/info/refs&amp;service=git-receive-pack</code></pre>
+</div></div>
+<div class="paragraph"><p>An example of a request to a submodule:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>$GIT_URL: http://example.com/git/repo.git/path/submodule.git
+URL request: http://example.com/git/repo.git/path/submodule.git/info/refs</code></pre>
+</div></div>
+<div class="paragraph"><p>Clients MUST strip a trailing <code>/</code>, if present, from the user supplied
+<code>$GIT_URL</code> string to prevent empty path tokens (<code>//</code>) from appearing
+in any URL sent to a server. Compatible clients MUST expand
+<code>$GIT_URL/info/refs</code> as <code>foo/info/refs</code> and not <code>foo//info/refs</code>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_authentication">Authentication</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Standard HTTP authentication is used if authentication is required
+to access a repository, and MAY be configured and enforced by the
+HTTP server software.</p></div>
+<div class="paragraph"><p>Because Git repositories are accessed by standard path components
+server administrators MAY use directory based permissions within
+their HTTP server to control repository access.</p></div>
+<div class="paragraph"><p>Clients SHOULD support Basic authentication as described by RFC 2617.
+Servers SHOULD support Basic authentication by relying upon the
+HTTP server placed in front of the Git server software.</p></div>
+<div class="paragraph"><p>Servers SHOULD NOT require HTTP cookies for the purposes of
+authentication or access control.</p></div>
+<div class="paragraph"><p>Clients and servers MAY support other common forms of HTTP based
+authentication, such as Digest authentication.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ssl">SSL</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Clients and servers SHOULD support SSL, particularly to protect
+passwords when relying on Basic HTTP authentication.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_session_state">Session State</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Git over HTTP protocol (much like HTTP itself) is stateless
+from the perspective of the HTTP server side. All state MUST be
+retained and managed by the client process. This permits simple
+round-robin load-balancing on the server side, without needing to
+worry about state management.</p></div>
+<div class="paragraph"><p>Clients MUST NOT require state management on the server side in
+order to function correctly.</p></div>
+<div class="paragraph"><p>Servers MUST NOT require HTTP cookies in order to function correctly.
+Clients MAY store and forward HTTP cookies during request processing
+as described by RFC 2616 (HTTP/1.1). Servers SHOULD ignore any
+cookies sent by a client.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_general_request_processing">General Request Processing</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Except where noted, all standard HTTP behavior SHOULD be assumed
+by both client and server. This includes (but is not necessarily
+limited to):</p></div>
+<div class="paragraph"><p>If there is no repository at <code>$GIT_URL</code>, or the resource pointed to by a
+location matching <code>$GIT_URL</code> does not exist, the server MUST NOT respond
+with <code>200 OK</code> response. A server SHOULD respond with
+<code>404 Not Found</code>, <code>410 Gone</code>, or any other suitable HTTP status code
+which does not imply the resource exists as requested.</p></div>
+<div class="paragraph"><p>If there is a repository at <code>$GIT_URL</code>, but access is not currently
+permitted, the server MUST respond with the <code>403 Forbidden</code> HTTP
+status code.</p></div>
+<div class="paragraph"><p>Servers SHOULD support both HTTP 1.0 and HTTP 1.1.
+Servers SHOULD support chunked encoding for both request and response
+bodies.</p></div>
+<div class="paragraph"><p>Clients SHOULD support both HTTP 1.0 and HTTP 1.1.
+Clients SHOULD support chunked encoding for both request and response
+bodies.</p></div>
+<div class="paragraph"><p>Servers MAY return ETag and/or Last-Modified headers.</p></div>
+<div class="paragraph"><p>Clients MAY revalidate cached entities by including If-Modified-Since
+and/or If-None-Match request headers.</p></div>
+<div class="paragraph"><p>Servers MAY return <code>304 Not Modified</code> if the relevant headers appear
+in the request and the entity has not changed. Clients MUST treat
+<code>304 Not Modified</code> identical to <code>200 OK</code> by reusing the cached entity.</p></div>
+<div class="paragraph"><p>Clients MAY reuse a cached entity without revalidation if the
+Cache-Control and/or Expires header permits caching. Clients and
+servers MUST follow RFC 2616 for cache controls.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_discovering_references">Discovering References</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>All HTTP clients MUST begin either a fetch or a push exchange by
+discovering the references available on the remote repository.</p></div>
+<div class="sect2">
+<h3 id="_dumb_clients">Dumb Clients</h3>
+<div class="paragraph"><p>HTTP clients that only support the "dumb" protocol MUST discover
+references by making a request for the special info/refs file of
+the repository.</p></div>
+<div class="paragraph"><p>Dumb HTTP clients MUST make a <code>GET</code> request to <code>$GIT_URL/info/refs</code>,
+without any search/query parameters.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>C: GET $GIT_URL/info/refs HTTP/1.0</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>S: 200 OK
+S:
+S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint
+S: d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master
+S: 2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0
+S: a3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}</code></pre>
+</div></div>
+<div class="paragraph"><p>The Content-Type of the returned info/refs entity SHOULD be
+<code>text/plain; charset=utf-8</code>, but MAY be any content type.
+Clients MUST NOT attempt to validate the returned Content-Type.
+Dumb servers MUST NOT return a return type starting with
+<code>application/x-git-</code>.</p></div>
+<div class="paragraph"><p>Cache-Control headers MAY be returned to disable caching of the
+returned entity.</p></div>
+<div class="paragraph"><p>When examining the response clients SHOULD only examine the HTTP
+status code. Valid responses are <code>200 OK</code>, or <code>304 Not Modified</code>.</p></div>
+<div class="paragraph"><p>The returned content is a UNIX formatted text file describing
+each ref and its known value. The file SHOULD be sorted by name
+according to the C locale ordering. The file SHOULD NOT include
+the default ref named <code>HEAD</code>.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>info_refs = *( ref_record )
+ref_record = any_ref / peeled_ref</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>any_ref = obj-id HTAB refname LF
+peeled_ref = obj-id HTAB refname LF
+ obj-id HTAB refname "^{}" LF</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_smart_clients">Smart Clients</h3>
+<div class="paragraph"><p>HTTP clients that support the "smart" protocol (or both the
+"smart" and "dumb" protocols) MUST discover references by making
+a parameterized request for the info/refs file of the repository.</p></div>
+<div class="paragraph"><p>The request MUST contain exactly one query parameter,
+<code>service=$servicename</code>, where <code>$servicename</code> MUST be the service
+name the client wishes to contact to complete the operation.
+The request MUST NOT contain additional query parameters.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0</code></pre>
+</div></div>
+<div class="paragraph"><p>dumb server reply:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>S: 200 OK
+S:
+S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint
+S: d049f6c27a2244e12041955e262a404c7faba355 refs/heads/master
+S: 2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0
+S: a3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}</code></pre>
+</div></div>
+<div class="paragraph"><p>smart server reply:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>S: 200 OK
+S: Content-Type: application/x-git-upload-pack-advertisement
+S: Cache-Control: no-cache
+S:
+S: 001e# service=git-upload-pack\n
+S: 0000
+S: 004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0multi_ack\n
+S: 003fd049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
+S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
+S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
+S: 0000</code></pre>
+</div></div>
+<div class="paragraph"><p>The client may send Extra Parameters (see
+<a href="gitprotocol-pack.html">gitprotocol-pack(5)</a>) as a colon-separated string
+in the Git-Protocol HTTP header.</p></div>
+<div class="paragraph"><p>Uses the <code>--http-backend-info-refs</code> option to
+<a href="git-upload-pack.html">git-upload-pack(1)</a>.</p></div>
+<div class="sect3">
+<h4 id="_dumb_server_response">Dumb Server Response</h4>
+<div class="paragraph"><p>Dumb servers MUST respond with the dumb server reply format.</p></div>
+<div class="paragraph"><p>See the prior section under dumb clients for a more detailed
+description of the dumb server response.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_smart_server_response">Smart Server Response</h4>
+<div class="paragraph"><p>If the server does not recognize the requested service name, or the
+requested service name has been disabled by the server administrator,
+the server MUST respond with the <code>403 Forbidden</code> HTTP status code.</p></div>
+<div class="paragraph"><p>Otherwise, smart servers MUST respond with the smart server reply
+format for the requested service name.</p></div>
+<div class="paragraph"><p>Cache-Control headers SHOULD be used to disable caching of the
+returned entity.</p></div>
+<div class="paragraph"><p>The Content-Type MUST be <code>application/x-$servicename-advertisement</code>.
+Clients SHOULD fall back to the dumb protocol if another content
+type is returned. When falling back to the dumb protocol clients
+SHOULD NOT make an additional request to <code>$GIT_URL/info/refs</code>, but
+instead SHOULD use the response already in hand. Clients MUST NOT
+continue if they do not support the dumb protocol.</p></div>
+<div class="paragraph"><p>Clients MUST validate the status code is either <code>200 OK</code> or
+<code>304 Not Modified</code>.</p></div>
+<div class="paragraph"><p>Clients MUST validate the first five bytes of the response entity
+matches the regex <code>^[0-9a-f]{4}#</code>. If this test fails, clients
+MUST NOT continue.</p></div>
+<div class="paragraph"><p>Clients MUST parse the entire response as a sequence of pkt-line
+records.</p></div>
+<div class="paragraph"><p>Clients MUST verify the first pkt-line is <code># service=$servicename</code>.
+Servers MUST set $servicename to be the request parameter value.
+Servers SHOULD include an LF at the end of this line.
+Clients MUST ignore an LF at the end of the line.</p></div>
+<div class="paragraph"><p>Servers MUST terminate the response with the magic <code>0000</code> end
+pkt-line marker.</p></div>
+<div class="paragraph"><p>The returned response is a pkt-line stream describing each ref and
+its known value. The stream SHOULD be sorted by name according to
+the C locale ordering. The stream SHOULD include the default ref
+named <code>HEAD</code> as the first ref. The stream MUST include capability
+declarations behind a NUL on the first ref.</p></div>
+<div class="paragraph"><p>The returned response contains "version 1" if "version=1" was sent as an
+Extra Parameter.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>smart_reply = PKT-LINE("# service=$servicename" LF)
+ "0000"
+ *1("version 1")
+ ref_list
+ "0000"
+ref_list = empty_list / non_empty_list</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>empty_list = PKT-LINE(zero-id SP "capabilities^{}" NUL cap-list LF)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>non_empty_list = PKT-LINE(obj-id SP name NUL cap_list LF)
+ *ref_record</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>cap-list = capability *(SP capability)
+capability = 1*(LC_ALPHA / DIGIT / "-" / "_")
+LC_ALPHA = %x61-7A</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>ref_record = any_ref / peeled_ref
+any_ref = PKT-LINE(obj-id SP name LF)
+peeled_ref = PKT-LINE(obj-id SP name LF)
+ PKT-LINE(obj-id SP name "^{}" LF</code></pre>
+</div></div>
+</div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_smart_service_git_upload_pack">Smart Service git-upload-pack</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This service reads from the repository pointed to by <code>$GIT_URL</code>.</p></div>
+<div class="paragraph"><p>Clients MUST first perform ref discovery with
+<code>$GIT_URL/info/refs?service=git-upload-pack</code>.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>C: POST $GIT_URL/git-upload-pack HTTP/1.0
+C: Content-Type: application/x-git-upload-pack-request
+C:
+C: 0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7\n
+C: 0032have 441b40d833fdfa93eb2908e52742248faf0ee993\n
+C: 0000</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>S: 200 OK
+S: Content-Type: application/x-git-upload-pack-result
+S: Cache-Control: no-cache
+S:
+S: ....ACK %s, continue
+S: ....NAK</code></pre>
+</div></div>
+<div class="paragraph"><p>Clients MUST NOT reuse or revalidate a cached response.
+Servers MUST include sufficient Cache-Control headers
+to prevent caching of the response.</p></div>
+<div class="paragraph"><p>Servers SHOULD support all capabilities defined here.</p></div>
+<div class="paragraph"><p>Clients MUST send at least one "want" command in the request body.
+Clients MUST NOT reference an id in a "want" command which did not
+appear in the response obtained through ref discovery unless the
+server advertises capability <code>allow-tip-sha1-in-want</code> or
+<code>allow-reachable-sha1-in-want</code>.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>compute_request = want_list
+ have_list
+ request_end
+request_end = "0000" / "done"</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>want_list = PKT-LINE(want SP cap_list LF)
+ *(want_pkt)
+want_pkt = PKT-LINE(want LF)
+want = "want" SP id
+cap_list = capability *(SP capability)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>have_list = *PKT-LINE("have" SP id LF)</code></pre>
+</div></div>
+<div class="paragraph"><p>TODO: Document this further.</p></div>
+<div class="sect2">
+<h3 id="_the_negotiation_algorithm">The Negotiation Algorithm</h3>
+<div class="paragraph"><p>The computation to select the minimal pack proceeds as follows
+(C = client, S = server):</p></div>
+<div class="paragraph"><p><em>init step:</em></p></div>
+<div class="paragraph"><p>C: Use ref discovery to obtain the advertised refs.</p></div>
+<div class="paragraph"><p>C: Place any object seen into set <code>advertised</code>.</p></div>
+<div class="paragraph"><p>C: Build an empty set, <code>common</code>, to hold the objects that are later
+ determined to be on both ends.</p></div>
+<div class="paragraph"><p>C: Build a set, <code>want</code>, of the objects from <code>advertised</code> the client
+ wants to fetch, based on what it saw during ref discovery.</p></div>
+<div class="paragraph"><p>C: Start a queue, <code>c_pending</code>, ordered by commit time (popping newest
+ first). Add all client refs. When a commit is popped from
+ the queue its parents SHOULD be automatically inserted back.
+ Commits MUST only enter the queue once.</p></div>
+<div class="paragraph"><p><em>one compute step:</em></p></div>
+<div class="paragraph"><p>C: Send one <code>$GIT_URL/git-upload-pack</code> request:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>C: 0032want &lt;want #1&gt;...............................
+C: 0032want &lt;want #2&gt;...............................
+....
+C: 0032have &lt;common #1&gt;.............................
+C: 0032have &lt;common #2&gt;.............................
+....
+C: 0032have &lt;have #1&gt;...............................
+C: 0032have &lt;have #2&gt;...............................
+....
+C: 0000</code></pre>
+</div></div>
+<div class="paragraph"><p>The stream is organized into "commands", with each command
+appearing by itself in a pkt-line. Within a command line,
+the text leading up to the first space is the command name,
+and the remainder of the line to the first LF is the value.
+Command lines are terminated with an LF as the last byte of
+the pkt-line value.</p></div>
+<div class="paragraph"><p>Commands MUST appear in the following order, if they appear
+at all in the request stream:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+"want"
+</p>
+</li>
+<li>
+<p>
+"have"
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>The stream is terminated by a pkt-line flush (<code>0000</code>).</p></div>
+<div class="paragraph"><p>A single "want" or "have" command MUST have one hex formatted
+object name as its value. Multiple object names MUST be sent by sending
+multiple commands. Object names MUST be given using the object format
+negotiated through the <code>object-format</code> capability (default SHA-1).</p></div>
+<div class="paragraph"><p>The <code>have</code> list is created by popping the first 32 commits
+from <code>c_pending</code>. Less can be supplied if <code>c_pending</code> empties.</p></div>
+<div class="paragraph"><p>If the client has sent 256 "have" commits and has not yet
+received one of those back from <code>s_common</code>, or the client has
+emptied <code>c_pending</code> it SHOULD include a "done" command to let
+the server know it won&#8217;t proceed:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>C: 0009done</code></pre>
+</div></div>
+<div class="paragraph"><p>S: Parse the git-upload-pack request:</p></div>
+<div class="paragraph"><p>Verify all objects in <code>want</code> are directly reachable from refs.</p></div>
+<div class="paragraph"><p>The server MAY walk backwards through history or through
+the reflog to permit slightly stale requests.</p></div>
+<div class="paragraph"><p>If no "want" objects are received, send an error:
+TODO: Define error if no "want" lines are requested.</p></div>
+<div class="paragraph"><p>If any "want" object is not reachable, send an error:
+TODO: Define error if an invalid "want" is requested.</p></div>
+<div class="paragraph"><p>Create an empty list, <code>s_common</code>.</p></div>
+<div class="paragraph"><p>If "have" was sent:</p></div>
+<div class="paragraph"><p>Loop through the objects in the order supplied by the client.</p></div>
+<div class="paragraph"><p>For each object, if the server has the object reachable from
+a ref, add it to <code>s_common</code>. If a commit is added to <code>s_common</code>,
+do not add any ancestors, even if they also appear in <code>have</code>.</p></div>
+<div class="paragraph"><p>S: Send the git-upload-pack response:</p></div>
+<div class="paragraph"><p>If the server has found a closed set of objects to pack or the
+request ends with "done", it replies with the pack.
+TODO: Document the pack based response</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>S: PACK...</code></pre>
+</div></div>
+<div class="paragraph"><p>The returned stream is the side-band-64k protocol supported
+by the git-upload-pack service, and the pack is embedded into
+stream 1. Progress messages from the server side MAY appear
+in stream 2.</p></div>
+<div class="paragraph"><p>Here a "closed set of objects" is defined to have at least
+one path from every "want" to at least one "common" object.</p></div>
+<div class="paragraph"><p>If the server needs more information, it replies with a
+status continue response:
+TODO: Document the non-pack response</p></div>
+<div class="paragraph"><p>C: Parse the upload-pack response:
+ TODO: Document parsing response</p></div>
+<div class="paragraph"><p><em>Do another compute step.</em></p></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_smart_service_git_receive_pack">Smart Service git-receive-pack</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This service reads from the repository pointed to by <code>$GIT_URL</code>.</p></div>
+<div class="paragraph"><p>Clients MUST first perform ref discovery with
+<code>$GIT_URL/info/refs?service=git-receive-pack</code>.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>C: POST $GIT_URL/git-receive-pack HTTP/1.0
+C: Content-Type: application/x-git-receive-pack-request
+C:
+C: ....0a53e9ddeaddad63ad106860237bbf53411d11a7 441b40d833fdfa93eb2908e52742248faf0ee993 refs/heads/maint\0 report-status
+C: 0000
+C: PACK....</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>S: 200 OK
+S: Content-Type: application/x-git-receive-pack-result
+S: Cache-Control: no-cache
+S:
+S: ....</code></pre>
+</div></div>
+<div class="paragraph"><p>Clients MUST NOT reuse or revalidate a cached response.
+Servers MUST include sufficient Cache-Control headers
+to prevent caching of the response.</p></div>
+<div class="paragraph"><p>Servers SHOULD support all capabilities defined here.</p></div>
+<div class="paragraph"><p>Clients MUST send at least one command in the request body.
+Within the command portion of the request body clients SHOULD send
+the id obtained through ref discovery as old_id.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>update_request = command_list
+ "PACK" &lt;binary data&gt;</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>command_list = PKT-LINE(command NUL cap_list LF)
+ *(command_pkt)
+command_pkt = PKT-LINE(command LF)
+cap_list = *(SP capability) SP</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>command = create / delete / update
+create = zero-id SP new_id SP name
+delete = old_id SP zero-id SP name
+update = old_id SP new_id SP name</code></pre>
+</div></div>
+<div class="paragraph"><p>TODO: Document this further.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_references">REFERENCES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p><a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738: Uniform Resource Locators (URL)</a>
+<a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616: Hypertext Transfer Protocol&#8201;&#8212;&#8201;HTTP/1.1</a></p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">SEE ALSO</h2>
+<div class="sectionbody">
+<div class="paragraph"><p><a href="gitprotocol-pack.html">gitprotocol-pack(5)</a>
+<a href="gitprotocol-capabilities.html">gitprotocol-capabilities(5)</a></p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/http-protocol.txt b/gitprotocol-http.txt
index cc5126cfe..ccc13f0a4 100644
--- a/technical/http-protocol.txt
+++ b/gitprotocol-http.txt
@@ -1,5 +1,19 @@
-HTTP transfer protocols
-=======================
+gitprotocol-http(5)
+===================
+
+NAME
+----
+gitprotocol-http - Git HTTP-based protocols
+
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+
+DESCRIPTION
+-----------
Git supports two HTTP based transfer protocols. A "dumb" protocol
which requires only a standard HTTP server on the server end of the
@@ -222,7 +236,7 @@ smart server reply:
S: 0000
The client may send Extra Parameters (see
-Documentation/technical/pack-protocol.txt) as a colon-separated string
+linkgit:gitprotocol-pack[5]) as a colon-separated string
in the Git-Protocol HTTP header.
Uses the `--http-backend-info-refs` option to
@@ -512,11 +526,18 @@ the id obtained through ref discovery as old_id.
TODO: Document this further.
-
-References
+REFERENCES
----------
http://www.ietf.org/rfc/rfc1738.txt[RFC 1738: Uniform Resource Locators (URL)]
http://www.ietf.org/rfc/rfc2616.txt[RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1]
-link:technical/pack-protocol.html
-link:technical/protocol-capabilities.html
+
+SEE ALSO
+--------
+
+linkgit:gitprotocol-pack[5]
+linkgit:gitprotocol-capabilities[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitprotocol-pack.html b/gitprotocol-pack.html
new file mode 100644
index 000000000..0dfa78382
--- /dev/null
+++ b/gitprotocol-pack.html
@@ -0,0 +1,1501 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitprotocol-pack(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitprotocol-pack(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitprotocol-pack -
+ How packs are transferred over-the-wire
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">&lt;over-the-wire-protocol&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Git supports transferring data in packfiles over the ssh://, git://, http:// and
+file:// transports. There exist two sets of protocols, one for pushing
+data from a client to a server and another for fetching data from a
+server to a client. The three transports (ssh, git, file) use the same
+protocol to transfer data. http is documented in <a href="gitprotocol-http.html">gitprotocol-http(5)</a>.</p></div>
+<div class="paragraph"><p>The processes invoked in the canonical Git implementation are <em>upload-pack</em>
+on the server side and <em>fetch-pack</em> on the client side for fetching data;
+then <em>receive-pack</em> on the server and <em>send-pack</em> on the client for pushing
+data. The protocol functions to have a server tell a client what is
+currently on the server, then for the two to negotiate the smallest amount
+of data to send in order to fully update one or the other.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_pkt_line_format">pkt-line Format</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The descriptions below build on the pkt-line format described in
+<a href="gitprotocol-common.html">gitprotocol-common(5)</a>. When the grammar indicate <code>PKT-LINE(...)</code>, unless
+otherwise noted the usual pkt-line LF rules apply: the sender SHOULD
+include a LF, but the receiver MUST NOT complain if it is not present.</p></div>
+<div class="paragraph"><p>An error packet is a special pkt-line that contains an error string.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> error-line = PKT-LINE("ERR" SP explanation-text)</code></pre>
+</div></div>
+<div class="paragraph"><p>Throughout the protocol, where <code>PKT-LINE(...)</code> is expected, an error packet MAY
+be sent. Once this packet is sent by a client or a server, the data transfer
+process defined in this protocol is terminated.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_transports">Transports</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>There are three transports over which the packfile protocol is
+initiated. The Git transport is a simple, unauthenticated server that
+takes the command (almost always <em>upload-pack</em>, though Git
+servers can be configured to be globally writable, in which <em>receive-
+pack</em> initiation is also allowed) with which the client wishes to
+communicate and executes it and connects it to the requesting
+process.</p></div>
+<div class="paragraph"><p>In the SSH transport, the client just runs the <em>upload-pack</em>
+or <em>receive-pack</em> process on the server over the SSH protocol and then
+communicates with that invoked process over the SSH connection.</p></div>
+<div class="paragraph"><p>The file:// transport runs the <em>upload-pack</em> or <em>receive-pack</em>
+process locally and communicates with it over a pipe.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_extra_parameters">Extra Parameters</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The protocol provides a mechanism in which clients can send additional
+information in its first message to the server. These are called "Extra
+Parameters", and are supported by the Git, SSH, and HTTP protocols.</p></div>
+<div class="paragraph"><p>Each Extra Parameter takes the form of <code>&lt;key&gt;=&lt;value&gt;</code> or <code>&lt;key&gt;</code>.</p></div>
+<div class="paragraph"><p>Servers that receive any such Extra Parameters MUST ignore all
+unrecognized keys. Currently, the only Extra Parameter recognized is
+"version" with a value of <em>1</em> or <em>2</em>. See <a href="gitprotocol-v2.html">gitprotocol-v2(5)</a> for more
+information on protocol version 2.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git_transport">Git Transport</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Git transport starts off by sending the command and repository
+on the wire using the pkt-line format, followed by a NUL byte and a
+hostname parameter, terminated by a NUL byte.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>0033git-upload-pack /project.git\0host=myserver.com\0</code></pre>
+</div></div>
+<div class="paragraph"><p>The transport may send Extra Parameters by adding an additional NUL
+byte, and then adding one or more NUL-terminated strings:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>003egit-upload-pack /project.git\0host=myserver.com\0\0version=1\0</code></pre>
+</div></div>
+<div class="openblock">
+<div class="content">
+<div class="literalblock">
+<div class="content">
+<pre><code>git-proto-request = request-command SP pathname NUL
+ [ host-parameter NUL ] [ NUL extra-parameters ]
+request-command = "git-upload-pack" / "git-receive-pack" /
+ "git-upload-archive" ; case sensitive
+pathname = *( %x01-ff ) ; exclude NUL
+host-parameter = "host=" hostname [ ":" port ]
+extra-parameters = 1*extra-parameter
+extra-parameter = 1*( %x01-ff ) NUL</code></pre>
+</div></div>
+</div></div>
+<div class="paragraph"><p>host-parameter is used for the
+git-daemon name based virtual hosting. See --interpolated-path
+option to git daemon, with the %H/%CH format characters.</p></div>
+<div class="paragraph"><p>Basically what the Git client is doing to connect to an <em>upload-pack</em>
+process on the server side over the Git protocol is this:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>$ echo -e -n \
+ "003agit-upload-pack /schacon/gitbook.git\0host=example.com\0" |
+ nc -v example.com 9418</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_ssh_transport">SSH Transport</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Initiating the upload-pack or receive-pack processes over SSH is
+executing the binary on the server via SSH remote execution.
+It is basically equivalent to running this:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>$ ssh git.example.com "git-upload-pack '/project.git'"</code></pre>
+</div></div>
+<div class="paragraph"><p>For a server to support Git pushing and pulling for a given user over
+SSH, that user needs to be able to execute one or both of those
+commands via the SSH shell that they are provided on login. On some
+systems, that shell access is limited to only being able to run those
+two commands, or even just one of them.</p></div>
+<div class="paragraph"><p>In an ssh:// format URI, it&#8217;s absolute in the URI, so the <em>/</em> after
+the host name (or port number) is sent as an argument, which is then
+read by the remote git-upload-pack exactly as is, so it&#8217;s effectively
+an absolute path in the remote filesystem.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code> git clone ssh://user@example.com/project.git
+ |
+ v
+ssh user@example.com "git-upload-pack '/project.git'"</code></pre>
+</div></div>
+<div class="paragraph"><p>In a "user@host:path" format URI, its relative to the user&#8217;s home
+directory, because the Git client will run:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code> git clone user@example.com:project.git
+ |
+ v
+ssh user@example.com "git-upload-pack 'project.git'"</code></pre>
+</div></div>
+<div class="paragraph"><p>The exception is if a <em>~</em> is used, in which case
+we execute it without the leading <em>/</em>.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code> ssh://user@example.com/~alice/project.git,
+ |
+ v
+ssh user@example.com "git-upload-pack '~alice/project.git'"</code></pre>
+</div></div>
+<div class="paragraph"><p>Depending on the value of the <code>protocol.version</code> configuration variable,
+Git may attempt to send Extra Parameters as a colon-separated string in
+the GIT_PROTOCOL environment variable. This is done only if
+the <code>ssh.variant</code> configuration variable indicates that the ssh command
+supports passing environment variables as an argument.</p></div>
+<div class="paragraph"><p>A few things to remember here:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+The "command name" is spelled with dash (e.g. git-upload-pack), but
+ this can be overridden by the client;
+</p>
+</li>
+<li>
+<p>
+The repository path is always quoted with single quotes.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_fetching_data_from_a_server">Fetching Data From a Server</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>When one Git repository wants to get data that a second repository
+has, the first can <em>fetch</em> from the second. This operation determines
+what data the server has that the client does not then streams that
+data down to the client in packfile format.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_reference_discovery">Reference Discovery</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>When the client initially connects the server will immediately respond
+with a version number (if "version=1" is sent as an Extra Parameter),
+and a listing of each reference it has (all branches and tags) along
+with the object name that each reference currently points to.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>$ echo -e -n "0045git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
+ nc -v example.com 9418
+000eversion 1
+00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack
+ side-band side-band-64k ofs-delta shallow no-progress include-tag
+00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
+003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
+003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
+003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
+003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
+0000</code></pre>
+</div></div>
+<div class="paragraph"><p>The returned response is a pkt-line stream describing each ref and
+its current value. The stream MUST be sorted by name according to
+the C locale ordering.</p></div>
+<div class="paragraph"><p>If HEAD is a valid ref, HEAD MUST appear as the first advertised
+ref. If HEAD is not a valid ref, HEAD MUST NOT appear in the
+advertisement list at all, but other refs may still appear.</p></div>
+<div class="paragraph"><p>The stream MUST include capability declarations behind a NUL on the
+first ref. The peeled value of a ref (that is "ref^{}") MUST be
+immediately after the ref itself, if presented. A conforming server
+MUST peel the ref if it&#8217;s an annotated tag.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> advertised-refs = *1("version 1")
+ (no-refs / list-of-refs)
+ *shallow
+ flush-pkt
+
+ no-refs = PKT-LINE(zero-id SP "capabilities^{}"
+ NUL capability-list)
+
+ list-of-refs = first-ref *other-ref
+ first-ref = PKT-LINE(obj-id SP refname
+ NUL capability-list)
+
+ other-ref = PKT-LINE(other-tip / other-peeled)
+ other-tip = obj-id SP refname
+ other-peeled = obj-id SP refname "^{}"
+
+ shallow = PKT-LINE("shallow" SP obj-id)
+
+ capability-list = capability *(SP capability)
+ capability = 1*(LC_ALPHA / DIGIT / "-" / "_")
+ LC_ALPHA = %x61-7A</code></pre>
+</div></div>
+<div class="paragraph"><p>Server and client MUST use lowercase for obj-id, both MUST treat obj-id
+as case-insensitive.</p></div>
+<div class="paragraph"><p>See protocol-capabilities.txt for a list of allowed server capabilities
+and descriptions.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_packfile_negotiation">Packfile Negotiation</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>After reference and capabilities discovery, the client can decide to
+terminate the connection by sending a flush-pkt, telling the server it can
+now gracefully terminate, and disconnect, when it does not need any pack
+data. This can happen with the ls-remote command, and also can happen when
+the client already is up to date.</p></div>
+<div class="paragraph"><p>Otherwise, it enters the negotiation phase, where the client and
+server determine what the minimal packfile necessary for transport is,
+by telling the server what objects it wants, its shallow objects
+(if any), and the maximum commit depth it wants (if any). The client
+will also send a list of the capabilities it wants to be in effect,
+out of what the server said it could do with the first <em>want</em> line.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> upload-request = want-list
+ *shallow-line
+ *1depth-request
+ [filter-request]
+ flush-pkt
+
+ want-list = first-want
+ *additional-want
+
+ shallow-line = PKT-LINE("shallow" SP obj-id)
+
+ depth-request = PKT-LINE("deepen" SP depth) /
+ PKT-LINE("deepen-since" SP timestamp) /
+ PKT-LINE("deepen-not" SP ref)
+
+ first-want = PKT-LINE("want" SP obj-id SP capability-list)
+ additional-want = PKT-LINE("want" SP obj-id)
+
+ depth = 1*DIGIT
+
+ filter-request = PKT-LINE("filter" SP filter-spec)</code></pre>
+</div></div>
+<div class="paragraph"><p>Clients MUST send all the obj-ids it wants from the reference
+discovery phase as <em>want</em> lines. Clients MUST send at least one
+<em>want</em> command in the request body. Clients MUST NOT mention an
+obj-id in a <em>want</em> command which did not appear in the response
+obtained through ref discovery.</p></div>
+<div class="paragraph"><p>The client MUST write all obj-ids which it only has shallow copies
+of (meaning that it does not have the parents of a commit) as
+<em>shallow</em> lines so that the server is aware of the limitations of
+the client&#8217;s history.</p></div>
+<div class="paragraph"><p>The client now sends the maximum commit history depth it wants for
+this transaction, which is the number of commits it wants from the
+tip of the history, if any, as a <em>deepen</em> line. A depth of 0 is the
+same as not making a depth request. The client does not want to receive
+any commits beyond this depth, nor does it want objects needed only to
+complete those commits. Commits whose parents are not received as a
+result are defined as shallow and marked as such in the server. This
+information is sent back to the client in the next step.</p></div>
+<div class="paragraph"><p>The client can optionally request that pack-objects omit various
+objects from the packfile using one of several filtering techniques.
+These are intended for use with partial clone and partial fetch
+operations. An object that does not meet a filter-spec value is
+omitted unless explicitly requested in a <em>want</em> line. See <code>rev-list</code>
+for possible filter-spec values.</p></div>
+<div class="paragraph"><p>Once all the <em>want&#8217;s and 'shallow&#8217;s (and optional 'deepen</em>) are
+transferred, clients MUST send a flush-pkt, to tell the server side
+that it is done sending the list.</p></div>
+<div class="paragraph"><p>Otherwise, if the client sent a positive depth request, the server
+will determine which commits will and will not be shallow and
+send this information to the client. If the client did not request
+a positive depth, this step is skipped.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> shallow-update = *shallow-line
+ *unshallow-line
+ flush-pkt
+
+ shallow-line = PKT-LINE("shallow" SP obj-id)
+
+ unshallow-line = PKT-LINE("unshallow" SP obj-id)</code></pre>
+</div></div>
+<div class="paragraph"><p>If the client has requested a positive depth, the server will compute
+the set of commits which are no deeper than the desired depth. The set
+of commits start at the client&#8217;s wants.</p></div>
+<div class="paragraph"><p>The server writes <em>shallow</em> lines for each
+commit whose parents will not be sent as a result. The server writes
+an <em>unshallow</em> line for each commit which the client has indicated is
+shallow, but is no longer shallow at the currently requested depth
+(that is, its parents will now be sent). The server MUST NOT mark
+as unshallow anything which the client has not indicated was shallow.</p></div>
+<div class="paragraph"><p>Now the client will send a list of the obj-ids it has using <em>have</em>
+lines, so the server can make a packfile that only contains the objects
+that the client needs. In multi_ack mode, the canonical implementation
+will send up to 32 of these at a time, then will send a flush-pkt. The
+canonical implementation will skip ahead and send the next 32 immediately,
+so that there is always a block of 32 "in-flight on the wire" at a time.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> upload-haves = have-list
+ compute-end
+
+ have-list = *have-line
+ have-line = PKT-LINE("have" SP obj-id)
+ compute-end = flush-pkt / PKT-LINE("done")</code></pre>
+</div></div>
+<div class="paragraph"><p>If the server reads <em>have</em> lines, it then will respond by ACKing any
+of the obj-ids the client said it had that the server also has. The
+server will ACK obj-ids differently depending on which ack mode is
+chosen by the client.</p></div>
+<div class="paragraph"><p>In multi_ack mode:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+the server will respond with <em>ACK obj-id continue</em> for any common
+ commits.
+</p>
+</li>
+<li>
+<p>
+once the server has found an acceptable common base commit and is
+ ready to make a packfile, it will blindly ACK all <em>have</em> obj-ids
+ back to the client.
+</p>
+</li>
+<li>
+<p>
+the server will then send a <em>NAK</em> and then wait for another response
+ from the client - either a <em>done</em> or another list of <em>have</em> lines.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>In multi_ack_detailed mode:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+the server will differentiate the ACKs where it is signaling
+ that it is ready to send data with <em>ACK obj-id ready</em> lines, and
+ signals the identified common commits with <em>ACK obj-id common</em> lines.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Without either multi_ack or multi_ack_detailed:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+upload-pack sends "ACK obj-id" on the first common object it finds.
+ After that it says nothing until the client gives it a "done".
+</p>
+</li>
+<li>
+<p>
+upload-pack sends "NAK" on a flush-pkt if no common object
+ has been found yet. If one has been found, and thus an ACK
+ was already sent, it&#8217;s silent on the flush-pkt.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>After the client has gotten enough ACK responses that it can determine
+that the server has enough information to send an efficient packfile
+(in the canonical implementation, this is determined when it has received
+enough ACKs that it can color everything left in the --date-order queue
+as common with the server, or the --date-order queue is empty), or the
+client determines that it wants to give up (in the canonical implementation,
+this is determined when the client sends 256 <em>have</em> lines without getting
+any of them ACKed by the server - meaning there is nothing in common and
+the server should just send all of its objects), then the client will send
+a <em>done</em> command. The <em>done</em> command signals to the server that the client
+is ready to receive its packfile data.</p></div>
+<div class="paragraph"><p>However, the 256 limit <strong>only</strong> turns on in the canonical client
+implementation if we have received at least one "ACK %s continue"
+during a prior round. This helps to ensure that at least one common
+ancestor is found before we give up entirely.</p></div>
+<div class="paragraph"><p>Once the <em>done</em> line is read from the client, the server will either
+send a final <em>ACK obj-id</em> or it will send a <em>NAK</em>. <em>obj-id</em> is the object
+name of the last commit determined to be common. The server only sends
+ACK after <em>done</em> if there is at least one common base and multi_ack or
+multi_ack_detailed is enabled. The server always sends NAK after <em>done</em>
+if there is no common base found.</p></div>
+<div class="paragraph"><p>Instead of <em>ACK</em> or <em>NAK</em>, the server may send an error message (for
+example, if it does not recognize an object in a <em>want</em> line received
+from the client).</p></div>
+<div class="paragraph"><p>Then the server will start sending its packfile data.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> server-response = *ack_multi ack / nak
+ ack_multi = PKT-LINE("ACK" SP obj-id ack_status)
+ ack_status = "continue" / "common" / "ready"
+ ack = PKT-LINE("ACK" SP obj-id)
+ nak = PKT-LINE("NAK")</code></pre>
+</div></div>
+<div class="paragraph"><p>A simple clone may look like this (with no <em>have</em> lines):</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
+ side-band-64k ofs-delta\n
+ C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
+ C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
+ C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
+ C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n
+ C: 0000
+ C: 0009done\n
+
+ S: 0008NAK\n
+ S: [PACKFILE]</code></pre>
+</div></div>
+<div class="paragraph"><p>An incremental update (fetch) response might look like this:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
+ side-band-64k ofs-delta\n
+ C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
+ C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
+ C: 0000
+ C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
+ C: [30 more have lines]
+ C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n
+ C: 0000
+
+ S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n
+ S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n
+ S: 0008NAK\n
+
+ C: 0009done\n
+
+ S: 0031ACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
+ S: [PACKFILE]</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_packfile_data">Packfile Data</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Now that the client and server have finished negotiation about what
+the minimal amount of data that needs to be sent to the client is, the server
+will construct and send the required data in packfile format.</p></div>
+<div class="paragraph"><p>See <a href="gitformat-pack.html">gitformat-pack(5)</a> for what the packfile itself actually looks like.</p></div>
+<div class="paragraph"><p>If <em>side-band</em> or <em>side-band-64k</em> capabilities have been specified by
+the client, the server will send the packfile data multiplexed.</p></div>
+<div class="paragraph"><p>Each packet starting with the packet-line length of the amount of data
+that follows, followed by a single byte specifying the sideband the
+following data is coming in on.</p></div>
+<div class="paragraph"><p>In <em>side-band</em> mode, it will send up to 999 data bytes plus 1 control
+code, for a total of up to 1000 bytes in a pkt-line. In <em>side-band-64k</em>
+mode it will send up to 65519 data bytes plus 1 control code, for a
+total of up to 65520 bytes in a pkt-line.</p></div>
+<div class="paragraph"><p>The sideband byte will be a <em>1</em>, <em>2</em> or a <em>3</em>. Sideband <em>1</em> will contain
+packfile data, sideband <em>2</em> will be used for progress information that the
+client will generally print to stderr and sideband <em>3</em> is used for error
+information.</p></div>
+<div class="paragraph"><p>If no <em>side-band</em> capability was specified, the server will stream the
+entire packfile without multiplexing.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_pushing_data_to_a_server">Pushing Data To a Server</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Pushing data to a server will invoke the <em>receive-pack</em> process on the
+server, which will allow the client to tell it which references it should
+update and then send all the data the server will need for those new
+references to be complete. Once all the data is received and validated,
+the server will then update its references to what the client specified.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_authentication">Authentication</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The protocol itself contains no authentication mechanisms. That is to be
+handled by the transport, such as SSH, before the <em>receive-pack</em> process is
+invoked. If <em>receive-pack</em> is configured over the Git transport, those
+repositories will be writable by anyone who can access that port (9418) as
+that transport is unauthenticated.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_reference_discovery_2">Reference Discovery</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The reference discovery phase is done nearly the same way as it is in the
+fetching protocol. Each reference obj-id and name on the server is sent
+in packet-line format to the client, followed by a flush-pkt. The only
+real difference is that the capability listing is different - the only
+possible values are <em>report-status</em>, <em>report-status-v2</em>, <em>delete-refs</em>,
+<em>ofs-delta</em>, <em>atomic</em> and <em>push-options</em>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_reference_update_request_and_packfile_transfer">Reference Update Request and Packfile Transfer</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Once the client knows what references the server is at, it can send a
+list of reference update requests. For each reference on the server
+that it wants to update, it sends a line listing the obj-id currently on
+the server, the obj-id the client would like to update it to and the name
+of the reference.</p></div>
+<div class="paragraph"><p>This list is followed by a flush-pkt.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> update-requests = *shallow ( command-list | push-cert )
+
+ shallow = PKT-LINE("shallow" SP obj-id)
+
+ command-list = PKT-LINE(command NUL capability-list)
+ *PKT-LINE(command)
+ flush-pkt
+
+ command = create / delete / update
+ create = zero-id SP new-id SP name
+ delete = old-id SP zero-id SP name
+ update = old-id SP new-id SP name
+
+ old-id = obj-id
+ new-id = obj-id
+
+ push-cert = PKT-LINE("push-cert" NUL capability-list LF)
+ PKT-LINE("certificate version 0.1" LF)
+ PKT-LINE("pusher" SP ident LF)
+ PKT-LINE("pushee" SP url LF)
+ PKT-LINE("nonce" SP nonce LF)
+ *PKT-LINE("push-option" SP push-option LF)
+ PKT-LINE(LF)
+ *PKT-LINE(command LF)
+ *PKT-LINE(gpg-signature-lines LF)
+ PKT-LINE("push-cert-end" LF)
+
+ push-option = 1*( VCHAR | SP )</code></pre>
+</div></div>
+<div class="paragraph"><p>If the server has advertised the <em>push-options</em> capability and the client has
+specified <em>push-options</em> as part of the capability list above, the client then
+sends its push options followed by a flush-pkt.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> push-options = *PKT-LINE(push-option) flush-pkt</code></pre>
+</div></div>
+<div class="paragraph"><p>For backwards compatibility with older Git servers, if the client sends a push
+cert and push options, it MUST send its push options both embedded within the
+push cert and after the push cert. (Note that the push options within the cert
+are prefixed, but the push options after the cert are not.) Both these lists
+MUST be the same, modulo the prefix.</p></div>
+<div class="paragraph"><p>After that the packfile that
+should contain all the objects that the server will need to complete the new
+references will be sent.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> packfile = "PACK" 28*(OCTET)</code></pre>
+</div></div>
+<div class="paragraph"><p>If the receiving end does not support delete-refs, the sending end MUST
+NOT ask for delete command.</p></div>
+<div class="paragraph"><p>If the receiving end does not support push-cert, the sending end
+MUST NOT send a push-cert command. When a push-cert command is
+sent, command-list MUST NOT be sent; the commands recorded in the
+push certificate is used instead.</p></div>
+<div class="paragraph"><p>The packfile MUST NOT be sent if the only command used is <em>delete</em>.</p></div>
+<div class="paragraph"><p>A packfile MUST be sent if either create or update command is used,
+even if the server already has all the necessary objects. In this
+case the client MUST send an empty packfile. The only time this
+is likely to happen is if the client is creating
+a new branch or a tag that points to an existing obj-id.</p></div>
+<div class="paragraph"><p>The server will receive the packfile, unpack it, then validate each
+reference that is being updated that it hasn&#8217;t changed while the request
+was being processed (the obj-id is still the same as the old-id), and
+it will run any update hooks to make sure that the update is acceptable.
+If all of that is fine, the server will then update the references.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_push_certificate">Push Certificate</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>A push certificate begins with a set of header lines. After the
+header and an empty line, the protocol commands follow, one per
+line. Note that the trailing LF in push-cert PKT-LINEs is <em>not</em>
+optional; it must be present.</p></div>
+<div class="paragraph"><p>Currently, the following header fields are defined:</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<code>pusher</code> ident
+</dt>
+<dd>
+<p>
+ Identify the GPG key in "Human Readable Name &lt;<a href="mailto:email@address">email@address</a>&gt;"
+ format.
+</p>
+</dd>
+<dt class="hdlist1">
+<code>pushee</code> url
+</dt>
+<dd>
+<p>
+ The repository URL (anonymized, if the URL contains
+ authentication material) the user who ran <code>git push</code>
+ intended to push into.
+</p>
+</dd>
+<dt class="hdlist1">
+<code>nonce</code> nonce
+</dt>
+<dd>
+<p>
+ The <em>nonce</em> string the receiving repository asked the
+ pushing user to include in the certificate, to prevent
+ replay attacks.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>The GPG signature lines are a detached signature for the contents
+recorded in the push certificate before the signature block begins.
+The detached signature is used to certify that the commands were
+given by the pusher, who must be the signer.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_report_status">Report Status</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>After receiving the pack data from the sender, the receiver sends a
+report if <em>report-status</em> or <em>report-status-v2</em> capability is in effect.
+It is a short listing of what happened in that update. It will first
+list the status of the packfile unpacking as either <em>unpack ok</em> or
+<em>unpack [error]</em>. Then it will list the status for each of the references
+that it tried to update. Each line is either <em>ok [refname]</em> if the
+update was successful, or <em>ng [refname] [error]</em> if the update was not.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> report-status = unpack-status
+ 1*(command-status)
+ flush-pkt
+
+ unpack-status = PKT-LINE("unpack" SP unpack-result)
+ unpack-result = "ok" / error-msg
+
+ command-status = command-ok / command-fail
+ command-ok = PKT-LINE("ok" SP refname)
+ command-fail = PKT-LINE("ng" SP refname SP error-msg)
+
+ error-msg = 1*(OCTET) ; where not "ok"</code></pre>
+</div></div>
+<div class="paragraph"><p>The <em>report-status-v2</em> capability extends the protocol by adding new option
+lines in order to support reporting of reference rewritten by the
+<em>proc-receive</em> hook. The <em>proc-receive</em> hook may handle a command for a
+pseudo-reference which may create or update one or more references, and each
+reference may have different name, different new-oid, and different old-oid.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> report-status-v2 = unpack-status
+ 1*(command-status-v2)
+ flush-pkt
+
+ unpack-status = PKT-LINE("unpack" SP unpack-result)
+ unpack-result = "ok" / error-msg
+
+ command-status-v2 = command-ok-v2 / command-fail
+ command-ok-v2 = command-ok
+ *option-line
+
+ command-ok = PKT-LINE("ok" SP refname)
+ command-fail = PKT-LINE("ng" SP refname SP error-msg)
+
+ error-msg = 1*(OCTET) ; where not "ok"
+
+ option-line = *1(option-refname)
+ *1(option-old-oid)
+ *1(option-new-oid)
+ *1(option-forced-update)
+
+ option-refname = PKT-LINE("option" SP "refname" SP refname)
+ option-old-oid = PKT-LINE("option" SP "old-oid" SP obj-id)
+ option-new-oid = PKT-LINE("option" SP "new-oid" SP obj-id)
+ option-force = PKT-LINE("option" SP "forced-update")</code></pre>
+</div></div>
+<div class="paragraph"><p>Updates can be unsuccessful for a number of reasons. The reference can have
+changed since the reference discovery phase was originally sent, meaning
+someone pushed in the meantime. The reference being pushed could be a
+non-fast-forward reference and the update hooks or configuration could be
+set to not allow that, etc. Also, some references can be updated while others
+can be rejected.</p></div>
+<div class="paragraph"><p>An example client/server communication might look like this:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> S: 006274730d410fcb6603ace96f1dc55ea6196122532d refs/heads/local\0report-status delete-refs ofs-delta\n
+ S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n
+ S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n
+ S: 003d74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n
+ S: 0000
+
+ C: 00677d1665144a3a975c05f1f43902ddaf084e784dbe 74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n
+ C: 006874730d410fcb6603ace96f1dc55ea6196122532d 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n
+ C: 0000
+ C: [PACKDATA]
+
+ S: 000eunpack ok\n
+ S: 0018ok refs/heads/debug\n
+ S: 002ang refs/heads/master non-fast-forward\n</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/pack-protocol.txt b/gitprotocol-pack.txt
index e13a2c064..dd4108b7a 100644
--- a/technical/pack-protocol.txt
+++ b/gitprotocol-pack.txt
@@ -1,11 +1,23 @@
-Packfile transfer protocols
-===========================
+gitprotocol-pack(5)
+===================
+
+NAME
+----
+gitprotocol-pack - How packs are transferred over-the-wire
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
Git supports transferring data in packfiles over the ssh://, git://, http:// and
file:// transports. There exist two sets of protocols, one for pushing
data from a client to a server and another for fetching data from a
server to a client. The three transports (ssh, git, file) use the same
-protocol to transfer data. http is documented in http-protocol.txt.
+protocol to transfer data. http is documented in linkgit:gitprotocol-http[5].
The processes invoked in the canonical Git implementation are 'upload-pack'
on the server side and 'fetch-pack' on the client side for fetching data;
@@ -18,7 +30,7 @@ pkt-line Format
---------------
The descriptions below build on the pkt-line format described in
-protocol-common.txt. When the grammar indicate `PKT-LINE(...)`, unless
+linkgit:gitprotocol-common[5]. When the grammar indicate `PKT-LINE(...)`, unless
otherwise noted the usual pkt-line LF rules apply: the sender SHOULD
include a LF, but the receiver MUST NOT complain if it is not present.
@@ -60,7 +72,7 @@ Each Extra Parameter takes the form of `<key>=<value>` or `<key>`.
Servers that receive any such Extra Parameters MUST ignore all
unrecognized keys. Currently, the only Extra Parameter recognized is
-"version" with a value of '1' or '2'. See protocol-v2.txt for more
+"version" with a value of '1' or '2'. See linkgit:gitprotocol-v2[5] for more
information on protocol version 2.
Git Transport
@@ -455,7 +467,7 @@ Now that the client and server have finished negotiation about what
the minimal amount of data that needs to be sent to the client is, the server
will construct and send the required data in packfile format.
-See pack-format.txt for what the packfile itself actually looks like.
+See linkgit:gitformat-pack[5] for what the packfile itself actually looks like.
If 'side-band' or 'side-band-64k' capabilities have been specified by
the client, the server will send the packfile data multiplexed.
@@ -707,3 +719,7 @@ An example client/server communication might look like this:
S: 0018ok refs/heads/debug\n
S: 002ang refs/heads/master non-fast-forward\n
----
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/gitprotocol-v2.html b/gitprotocol-v2.html
new file mode 100644
index 000000000..ffd59e1ca
--- /dev/null
+++ b/gitprotocol-v2.html
@@ -0,0 +1,1504 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>gitprotocol-v2(5)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+gitprotocol-v2(5) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>gitprotocol-v2 -
+ Git Wire Protocol, Version 2
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">&lt;over-the-wire-protocol&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This document presents a specification for a version 2 of Git&#8217;s wire
+protocol. Protocol v2 will improve upon v1 in the following ways:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Instead of multiple service names, multiple commands will be
+ supported by a single service
+</p>
+</li>
+<li>
+<p>
+Easily extendable as capabilities are moved into their own section
+ of the protocol, no longer being hidden behind a NUL byte and
+ limited by the size of a pkt-line
+</p>
+</li>
+<li>
+<p>
+Separate out other information hidden behind NUL bytes (e.g. agent
+ string as a capability and symrefs can be requested using <em>ls-refs</em>)
+</p>
+</li>
+<li>
+<p>
+Reference advertisement will be omitted unless explicitly requested
+</p>
+</li>
+<li>
+<p>
+ls-refs command to explicitly request some refs
+</p>
+</li>
+<li>
+<p>
+Designed with http and stateless-rpc in mind. With clear flush
+ semantics the http remote helper can simply act as a proxy
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>In protocol v2 communication is command oriented. When first contacting a
+server a list of capabilities will advertised. Some of these capabilities
+will be commands which a client can request be executed. Once a command
+has completed, a client can reuse the connection and request that other
+commands be executed.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_packet_line_framing">Packet-Line Framing</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>All communication is done using packet-line framing, just as in v1. See
+<a href="gitprotocol-pack.html">gitprotocol-pack(5)</a> and <a href="gitprotocol-common.html">gitprotocol-common(5)</a> for more information.</p></div>
+<div class="paragraph"><p>In protocol v2 these special packets will have the following semantics:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+<em>0000</em> Flush Packet (flush-pkt) - indicates the end of a message
+</p>
+</li>
+<li>
+<p>
+<em>0001</em> Delimiter Packet (delim-pkt) - separates sections of a message
+</p>
+</li>
+<li>
+<p>
+<em>0002</em> Response End Packet (response-end-pkt) - indicates the end of a
+ response for stateless connections
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_initial_client_request">Initial Client Request</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>In general a client can request to speak protocol v2 by sending
+<code>version=2</code> through the respective side-channel for the transport being
+used which inevitably sets <code>GIT_PROTOCOL</code>. More information can be
+found in <a href="gitprotocol-pack.html">gitprotocol-pack(5)</a> and <a href="gitprotocol-http.html">gitprotocol-http(5)</a>, as well as the
+<code>GIT_PROTOCOL</code> definition in <code>git.txt</code>. In all cases the
+response from the server is the capability advertisement.</p></div>
+<div class="sect2">
+<h3 id="_git_transport">Git Transport</h3>
+<div class="paragraph"><p>When using the git:// transport, you can request to use protocol v2 by
+sending "version=2" as an extra parameter:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>003egit-upload-pack /project.git\0host=myserver.com\0\0version=2\0</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_ssh_and_file_transport">SSH and File Transport</h3>
+<div class="paragraph"><p>When using either the ssh:// or file:// transport, the GIT_PROTOCOL
+environment variable must be set explicitly to include "version=2".
+The server may need to be configured to allow this environment variable
+to pass.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_http_transport">HTTP Transport</h3>
+<div class="paragraph"><p>When using the http:// or https:// transport a client makes a "smart"
+info/refs request as described in <a href="gitprotocol-http.html">gitprotocol-http(5)</a> and requests that
+v2 be used by supplying "version=2" in the <code>Git-Protocol</code> header.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0
+C: Git-Protocol: version=2</code></pre>
+</div></div>
+<div class="paragraph"><p>A v2 server would reply:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>S: 200 OK
+S: &lt;Some headers&gt;
+S: ...
+S:
+S: 000eversion 2\n
+S: &lt;capability-advertisement&gt;</code></pre>
+</div></div>
+<div class="paragraph"><p>Subsequent requests are then made directly to the service
+<code>$GIT_URL/git-upload-pack</code>. (This works the same for git-receive-pack).</p></div>
+<div class="paragraph"><p>Uses the <code>--http-backend-info-refs</code> option to
+<a href="git-upload-pack.html">git-upload-pack(1)</a>.</p></div>
+<div class="paragraph"><p>The server may need to be configured to pass this header&#8217;s contents via
+the <code>GIT_PROTOCOL</code> variable. See the discussion in <code>git-http-backend.txt</code>.</p></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_capability_advertisement">Capability Advertisement</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>A server which decides to communicate (based on a request from a client)
+using protocol version 2, notifies the client by sending a version string
+in its initial response followed by an advertisement of its capabilities.
+Each capability is a key with an optional value. Clients must ignore all
+unknown keys. Semantics of unknown values are left to the definition of
+each key. Some capabilities will describe commands which can be requested
+to be executed by the client.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>capability-advertisement = protocol-version
+ capability-list
+ flush-pkt</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>protocol-version = PKT-LINE("version 2" LF)
+capability-list = *capability
+capability = PKT-LINE(key[=value] LF)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>key = 1*(ALPHA | DIGIT | "-_")
+value = 1*(ALPHA | DIGIT | " -_.,?\/{}[]()&lt;&gt;!@#$%^&amp;*+=:;")</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_command_request">Command Request</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>After receiving the capability advertisement, a client can then issue a
+request to select the command it wants with any particular capabilities
+or arguments. There is then an optional section where the client can
+provide any command specific parameters or queries. Only a single
+command can be requested at a time.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>request = empty-request | command-request
+empty-request = flush-pkt
+command-request = command
+ capability-list
+ delim-pkt
+ command-args
+ flush-pkt
+command = PKT-LINE("command=" key LF)
+command-args = *command-specific-arg</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>command-specific-args are packet line framed arguments defined by
+each individual command.</code></pre>
+</div></div>
+<div class="paragraph"><p>The server will then check to ensure that the client&#8217;s request is
+comprised of a valid command as well as valid capabilities which were
+advertised. If the request is valid the server will then execute the
+command. A server MUST wait till it has received the client&#8217;s entire
+request before issuing a response. The format of the response is
+determined by the command being executed, but in all cases a flush-pkt
+indicates the end of the response.</p></div>
+<div class="paragraph"><p>When a command has finished, and the client has received the entire
+response from the server, a client can either request that another
+command be executed or can terminate the connection. A client may
+optionally send an empty request consisting of just a flush-pkt to
+indicate that no more requests will be made.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_capabilities">Capabilities</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>There are two different types of capabilities: normal capabilities,
+which can be used to convey information or alter the behavior of a
+request, and commands, which are the core actions that a client wants to
+perform (fetch, push, etc).</p></div>
+<div class="paragraph"><p>Protocol version 2 is stateless by default. This means that all commands
+must only last a single round and be stateless from the perspective of the
+server side, unless the client has requested a capability indicating that
+state should be maintained by the server. Clients MUST NOT require state
+management on the server side in order to function correctly. This
+permits simple round-robin load-balancing on the server side, without
+needing to worry about state management.</p></div>
+<div class="sect2">
+<h3 id="_agent">agent</h3>
+<div class="paragraph"><p>The server can advertise the <code>agent</code> capability with a value <code>X</code> (in the
+form <code>agent=X</code>) to notify the client that the server is running version
+<code>X</code>. The client may optionally send its own agent string by including
+the <code>agent</code> capability with a value <code>Y</code> (in the form <code>agent=Y</code>) in its
+request to the server (but it MUST NOT do so if the server did not
+advertise the agent capability). The <code>X</code> and <code>Y</code> strings may contain any
+printable ASCII characters except space (i.e., the byte range 32 &lt; x &lt;
+127), and are typically of the form "package/version" (e.g.,
+"git/1.8.3.1"). The agent strings are purely informative for statistics
+and debugging purposes, and MUST NOT be used to programmatically assume
+the presence or absence of particular features.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_ls_refs">ls-refs</h3>
+<div class="paragraph"><p><code>ls-refs</code> is the command used to request a reference advertisement in v2.
+Unlike the current reference advertisement, ls-refs takes in arguments
+which can be used to limit the refs sent from the server.</p></div>
+<div class="paragraph"><p>Additional features not supported in the base command will be advertised
+as the value of the command in the capability advertisement in the form
+of a space separated list of features: "&lt;command&gt;=&lt;feature 1&gt; &lt;feature 2&gt;"</p></div>
+<div class="paragraph"><p>ls-refs takes in the following arguments:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>symrefs
+ In addition to the object pointed by it, show the underlying ref
+ pointed by it when showing a symbolic ref.
+peel
+ Show peeled tags.
+ref-prefix &lt;prefix&gt;
+ When specified, only references having a prefix matching one of
+ the provided prefixes are displayed. Multiple instances may be
+ given, in which case references matching any prefix will be
+ shown. Note that this is purely for optimization; a server MAY
+ show refs not matching the prefix if it chooses, and clients
+ should filter the result themselves.</code></pre>
+</div></div>
+<div class="paragraph"><p>If the <em>unborn</em> feature is advertised the following argument can be
+included in the client&#8217;s request.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>unborn
+ The server will send information about HEAD even if it is a symref
+ pointing to an unborn branch in the form "unborn HEAD
+ symref-target:&lt;target&gt;".</code></pre>
+</div></div>
+<div class="paragraph"><p>The output of ls-refs is as follows:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>output = *ref
+ flush-pkt
+obj-id-or-unborn = (obj-id | "unborn")
+ref = PKT-LINE(obj-id-or-unborn SP refname *(SP ref-attribute) LF)
+ref-attribute = (symref | peeled)
+symref = "symref-target:" symref-target
+peeled = "peeled:" obj-id</code></pre>
+</div></div>
+</div>
+<div class="sect2">
+<h3 id="_fetch">fetch</h3>
+<div class="paragraph"><p><code>fetch</code> is the command used to fetch a packfile in v2. It can be looked
+at as a modified version of the v1 fetch where the ref-advertisement is
+stripped out (since the <code>ls-refs</code> command fills that role) and the
+message format is tweaked to eliminate redundancies and permit easy
+addition of future extensions.</p></div>
+<div class="paragraph"><p>Additional features not supported in the base command will be advertised
+as the value of the command in the capability advertisement in the form
+of a space separated list of features: "&lt;command&gt;=&lt;feature 1&gt; &lt;feature 2&gt;"</p></div>
+<div class="paragraph"><p>A <code>fetch</code> request can take the following arguments:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>want &lt;oid&gt;
+ Indicates to the server an object which the client wants to
+ retrieve. Wants can be anything and are not limited to
+ advertised objects.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>have &lt;oid&gt;
+ Indicates to the server an object which the client has locally.
+ This allows the server to make a packfile which only contains
+ the objects that the client needs. Multiple 'have' lines can be
+ supplied.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>done
+ Indicates to the server that negotiation should terminate (or
+ not even begin if performing a clone) and that the server should
+ use the information supplied in the request to construct the
+ packfile.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>thin-pack
+ Request that a thin pack be sent, which is a pack with deltas
+ which reference base objects not contained within the pack (but
+ are known to exist at the receiving end). This can reduce the
+ network traffic significantly, but it requires the receiving end
+ to know how to "thicken" these packs by adding the missing bases
+ to the pack.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>no-progress
+ Request that progress information that would normally be sent on
+ side-band channel 2, during the packfile transfer, should not be
+ sent. However, the side-band channel 3 is still used for error
+ responses.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>include-tag
+ Request that annotated tags should be sent if the objects they
+ point to are being sent.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>ofs-delta
+ Indicate that the client understands PACKv2 with delta referring
+ to its base by position in pack rather than by an oid. That is,
+ they can read OBJ_OFS_DELTA (aka type 6) in a packfile.</code></pre>
+</div></div>
+<div class="paragraph"><p>If the <em>shallow</em> feature is advertised the following arguments can be
+included in the clients request as well as the potential addition of the
+<em>shallow-info</em> section in the server&#8217;s response as explained below.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>shallow &lt;oid&gt;
+ A client must notify the server of all commits for which it only
+ has shallow copies (meaning that it doesn't have the parents of
+ a commit) by supplying a 'shallow &lt;oid&gt;' line for each such
+ object so that the server is aware of the limitations of the
+ client's history. This is so that the server is aware that the
+ client may not have all objects reachable from such commits.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>deepen &lt;depth&gt;
+ Requests that the fetch/clone should be shallow having a commit
+ depth of &lt;depth&gt; relative to the remote side.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>deepen-relative
+ Requests that the semantics of the "deepen" command be changed
+ to indicate that the depth requested is relative to the client's
+ current shallow boundary, instead of relative to the requested
+ commits.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>deepen-since &lt;timestamp&gt;
+ Requests that the shallow clone/fetch should be cut at a
+ specific time, instead of depth. Internally it's equivalent to
+ doing "git rev-list --max-age=&lt;timestamp&gt;". Cannot be used with
+ "deepen".</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>deepen-not &lt;rev&gt;
+ Requests that the shallow clone/fetch should be cut at a
+ specific revision specified by '&lt;rev&gt;', instead of a depth.
+ Internally it's equivalent of doing "git rev-list --not &lt;rev&gt;".
+ Cannot be used with "deepen", but can be used with
+ "deepen-since".</code></pre>
+</div></div>
+<div class="paragraph"><p>If the <em>filter</em> feature is advertised, the following argument can be
+included in the client&#8217;s request:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>filter &lt;filter-spec&gt;
+ Request that various objects from the packfile be omitted
+ using one of several filtering techniques. These are intended
+ for use with partial clone and partial fetch operations. See
+ `rev-list` for possible "filter-spec" values. When communicating
+ with other processes, senders SHOULD translate scaled integers
+ (e.g. "1k") into a fully-expanded form (e.g. "1024") to aid
+ interoperability with older receivers that may not understand
+ newly-invented scaling suffixes. However, receivers SHOULD
+ accept the following suffixes: 'k', 'm', and 'g' for 1024,
+ 1048576, and 1073741824, respectively.</code></pre>
+</div></div>
+<div class="paragraph"><p>If the <em>ref-in-want</em> feature is advertised, the following argument can
+be included in the client&#8217;s request as well as the potential addition of
+the <em>wanted-refs</em> section in the server&#8217;s response as explained below.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>want-ref &lt;ref&gt;
+ Indicates to the server that the client wants to retrieve a
+ particular ref, where &lt;ref&gt; is the full name of a ref on the
+ server.</code></pre>
+</div></div>
+<div class="paragraph"><p>If the <em>sideband-all</em> feature is advertised, the following argument can be
+included in the client&#8217;s request:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>sideband-all
+ Instruct the server to send the whole response multiplexed, not just
+ the packfile section. All non-flush and non-delim PKT-LINE in the
+ response (not only in the packfile section) will then start with a byte
+ indicating its sideband (1, 2, or 3), and the server may send "0005\2"
+ (a PKT-LINE of sideband 2 with no payload) as a keepalive packet.</code></pre>
+</div></div>
+<div class="paragraph"><p>If the <em>packfile-uris</em> feature is advertised, the following argument
+can be included in the client&#8217;s request as well as the potential
+addition of the <em>packfile-uris</em> section in the server&#8217;s response as
+explained below.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>packfile-uris &lt;comma-separated list of protocols&gt;
+ Indicates to the server that the client is willing to receive
+ URIs of any of the given protocols in place of objects in the
+ sent packfile. Before performing the connectivity check, the
+ client should download from all given URIs. Currently, the
+ protocols supported are "http" and "https".</code></pre>
+</div></div>
+<div class="paragraph"><p>If the <em>wait-for-done</em> feature is advertised, the following argument
+can be included in the client&#8217;s request.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>wait-for-done
+ Indicates to the server that it should never send "ready", but
+ should wait for the client to say "done" before sending the
+ packfile.</code></pre>
+</div></div>
+<div class="paragraph"><p>The response of <code>fetch</code> is broken into a number of sections separated by
+delimiter packets (0001), with each section beginning with its section
+header. Most sections are sent only when the packfile is sent.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>output = acknowledgements flush-pkt |
+ [acknowledgments delim-pkt] [shallow-info delim-pkt]
+ [wanted-refs delim-pkt] [packfile-uris delim-pkt]
+ packfile flush-pkt</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>acknowledgments = PKT-LINE("acknowledgments" LF)
+ (nak | *ack)
+ (ready)
+ready = PKT-LINE("ready" LF)
+nak = PKT-LINE("NAK" LF)
+ack = PKT-LINE("ACK" SP obj-id LF)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>shallow-info = PKT-LINE("shallow-info" LF)
+ *PKT-LINE((shallow | unshallow) LF)
+shallow = "shallow" SP obj-id
+unshallow = "unshallow" SP obj-id</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>wanted-refs = PKT-LINE("wanted-refs" LF)
+ *PKT-LINE(wanted-ref LF)
+wanted-ref = obj-id SP refname</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>packfile-uris = PKT-LINE("packfile-uris" LF) *packfile-uri
+packfile-uri = PKT-LINE(40*(HEXDIGIT) SP *%x20-ff LF)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>packfile = PKT-LINE("packfile" LF)
+ *PKT-LINE(%x01-03 *%x00-ff)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>acknowledgments section
+ * If the client determines that it is finished with negotiations by
+ sending a "done" line (thus requiring the server to send a packfile),
+ the acknowledgments sections MUST be omitted from the server's
+ response.</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Always begins with the section header "acknowledgments"
+</p>
+</li>
+<li>
+<p>
+The server will respond with "NAK" if none of the object ids sent
+ as have lines were common.
+</p>
+</li>
+<li>
+<p>
+The server will respond with "ACK obj-id" for all of the
+ object ids sent as have lines which are common.
+</p>
+</li>
+<li>
+<p>
+A response cannot have both "ACK" lines as well as a "NAK"
+ line.
+</p>
+</li>
+<li>
+<p>
+The server will respond with a "ready" line indicating that
+ the server has found an acceptable common base and is ready to
+ make and send a packfile (which will be found in the packfile
+ section of the same response)
+</p>
+</li>
+<li>
+<p>
+If the server has found a suitable cut point and has decided
+ to send a "ready" line, then the server can decide to (as an
+ optimization) omit any "ACK" lines it would have sent during
+ its response. This is because the server will have already
+ determined the objects it plans to send to the client and no
+ further negotiation is needed.
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>shallow-info section
+ * If the client has requested a shallow fetch/clone, a shallow
+ client requests a fetch or the server is shallow then the
+ server's response may include a shallow-info section. The
+ shallow-info section will be included if (due to one of the
+ above conditions) the server needs to inform the client of any
+ shallow boundaries or adjustments to the clients already
+ existing shallow boundaries.</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Always begins with the section header "shallow-info"
+</p>
+</li>
+<li>
+<p>
+If a positive depth is requested, the server will compute the
+ set of commits which are no deeper than the desired depth.
+</p>
+</li>
+<li>
+<p>
+The server sends a "shallow obj-id" line for each commit whose
+ parents will not be sent in the following packfile.
+</p>
+</li>
+<li>
+<p>
+The server sends an "unshallow obj-id" line for each commit
+ which the client has indicated is shallow, but is no longer
+ shallow as a result of the fetch (due to its parents being
+ sent in the following packfile).
+</p>
+</li>
+<li>
+<p>
+The server MUST NOT send any "unshallow" lines for anything
+ which the client has not indicated was shallow as a part of
+ its request.
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>wanted-refs section
+ * This section is only included if the client has requested a
+ ref using a 'want-ref' line and if a packfile section is also
+ included in the response.</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Always begins with the section header "wanted-refs".
+</p>
+</li>
+<li>
+<p>
+The server will send a ref listing ("&lt;oid&gt; &lt;refname&gt;") for
+ each reference requested using <em>want-ref</em> lines.
+</p>
+</li>
+<li>
+<p>
+The server MUST NOT send any refs which were not requested
+ using <em>want-ref</em> lines.
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>packfile-uris section
+ * This section is only included if the client sent
+ 'packfile-uris' and the server has at least one such URI to
+ send.</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Always begins with the section header "packfile-uris".
+</p>
+</li>
+<li>
+<p>
+For each URI the server sends, it sends a hash of the pack&#8217;s
+ contents (as output by git index-pack) followed by the URI.
+</p>
+</li>
+<li>
+<p>
+The hashes are 40 hex characters long. When Git upgrades to a new
+ hash algorithm, this might need to be updated. (It should match
+ whatever index-pack outputs after "pack\t" or "keep\t".
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>packfile section
+ * This section is only included if the client has sent 'want'
+ lines in its request and either requested that no more
+ negotiation be done by sending 'done' or if the server has
+ decided it has found a sufficient cut point to produce a
+ packfile.</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Always begins with the section header "packfile"
+</p>
+</li>
+<li>
+<p>
+The transmission of the packfile begins immediately after the
+ section header
+</p>
+</li>
+<li>
+<p>
+The data transfer of the packfile is always multiplexed, using
+ the same semantics of the <em>side-band-64k</em> capability from
+ protocol version 1. This means that each packet, during the
+ packfile data stream, is made up of a leading 4-byte pkt-line
+ length (typical of the pkt-line format), followed by a 1-byte
+ stream code, followed by the actual data.
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>The stream code can be one of:
+ 1 - pack data
+ 2 - progress messages
+ 3 - fatal error message just before stream aborts</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+<div class="sect2">
+<h3 id="_server_option">server-option</h3>
+<div class="paragraph"><p>If advertised, indicates that any number of server specific options can be
+included in a request. This is done by sending each option as a
+"server-option=&lt;option&gt;" capability line in the capability-list section of
+a request.</p></div>
+<div class="paragraph"><p>The provided options must not contain a NUL or LF character.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_object_format"> object-format</h3>
+<div class="paragraph"><p>The server can advertise the <code>object-format</code> capability with a value <code>X</code> (in the
+form <code>object-format=X</code>) to notify the client that the server is able to deal
+with objects using hash algorithm X. If not specified, the server is assumed to
+only handle SHA-1. If the client would like to use a hash algorithm other than
+SHA-1, it should specify its object-format string.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_session_id_lt_session_id_gt">session-id=&lt;session id&gt;</h3>
+<div class="paragraph"><p>The server may advertise a session ID that can be used to identify this process
+across multiple requests. The client may advertise its own session ID back to
+the server as well.</p></div>
+<div class="paragraph"><p>Session IDs should be unique to a given process. They must fit within a
+packet-line, and must not contain non-printable or whitespace characters. The
+current implementation uses trace2 session IDs (see
+<a href="api-trace2.html">api-trace2</a> for details), but this may change and users of
+the session ID should not rely on this fact.</p></div>
+</div>
+<div class="sect2">
+<h3 id="_object_info">object-info</h3>
+<div class="paragraph"><p><code>object-info</code> is the command to retrieve information about one or more objects.
+Its main purpose is to allow a client to make decisions based on this
+information without having to fully fetch objects. Object size is the only
+information that is currently supported.</p></div>
+<div class="paragraph"><p>An <code>object-info</code> request takes the following arguments:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>size
+Requests size information to be returned for each listed object id.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>oid &lt;oid&gt;
+Indicates to the server an object which the client wants to obtain
+information for.</code></pre>
+</div></div>
+<div class="paragraph"><p>The response of <code>object-info</code> is a list of the requested object ids
+and associated requested information, each separated by a single space.</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>output = info flush-pkt</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>info = PKT-LINE(attrs) LF)
+ *PKT-LINE(obj-info LF)</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>attrs = attr | attrs SP attrs</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>attr = "size"</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>obj-info = obj-id SP obj-size</code></pre>
+</div></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_git">GIT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the <a href="git.html">git(1)</a> suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/protocol-v2.txt b/gitprotocol-v2.txt
index 8a877d27e..c9c0f9160 100644
--- a/technical/protocol-v2.txt
+++ b/gitprotocol-v2.txt
@@ -1,5 +1,17 @@
-Git Wire Protocol, Version 2
-============================
+gitprotocol-v2(5)
+=================
+
+NAME
+----
+gitprotocol-v2 - Git Wire Protocol, Version 2
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
This document presents a specification for a version 2 of Git's wire
protocol. Protocol v2 will improve upon v1 in the following ways:
@@ -26,8 +38,7 @@ Packet-Line Framing
-------------------
All communication is done using packet-line framing, just as in v1. See
-`Documentation/technical/pack-protocol.txt` and
-`Documentation/technical/protocol-common.txt` for more information.
+linkgit:gitprotocol-pack[5] and linkgit:gitprotocol-common[5] for more information.
In protocol v2 these special packets will have the following semantics:
@@ -42,7 +53,7 @@ Initial Client Request
In general a client can request to speak protocol v2 by sending
`version=2` through the respective side-channel for the transport being
used which inevitably sets `GIT_PROTOCOL`. More information can be
-found in `pack-protocol.txt` and `http-protocol.txt`, as well as the
+found in linkgit:gitprotocol-pack[5] and linkgit:gitprotocol-http[5], as well as the
`GIT_PROTOCOL` definition in `git.txt`. In all cases the
response from the server is the capability advertisement.
@@ -66,7 +77,7 @@ HTTP Transport
~~~~~~~~~~~~~~
When using the http:// or https:// transport a client makes a "smart"
-info/refs request as described in `http-protocol.txt` and requests that
+info/refs request as described in linkgit:gitprotocol-http[5] and requests that
v2 be used by supplying "version=2" in the `Git-Protocol` header.
C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0
@@ -566,3 +577,7 @@ and associated requested information, each separated by a single space.
attr = "size"
obj-info = obj-id SP obj-size
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/howto-index.html b/howto-index.html
index c6af00770..2671a5f60 100644
--- a/howto-index.html
+++ b/howto-index.html
@@ -4,7 +4,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 10.1.4" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
<title>Git Howto Index</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -894,7 +894,7 @@ later validate it.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-06-27 10:23:00 PDT
+ 2022-08-18 14:11:08 PDT
</div>
</div>
</body>
diff --git a/howto/coordinate-embargoed-releases.html b/howto/coordinate-embargoed-releases.html
index aacf4a9c8..3ea35c8ee 100644
--- a/howto/coordinate-embargoed-releases.html
+++ b/howto/coordinate-embargoed-releases.html
@@ -873,7 +873,7 @@ Thanks,
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:49 PDT
+ 2022-08-18 14:11:39 PDT
</div>
</div>
</body>
diff --git a/howto/keep-canonical-history-correct.html b/howto/keep-canonical-history-correct.html
index 5c8ef0023..a54aefd76 100644
--- a/howto/keep-canonical-history-correct.html
+++ b/howto/keep-canonical-history-correct.html
@@ -938,7 +938,7 @@ tip of your <em>master</em> again and redo the two merges:</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:48 PDT
+ 2022-08-18 14:11:39 PDT
</div>
</div>
</body>
diff --git a/howto/maintain-git.html b/howto/maintain-git.html
index 1302d89e4..78f48dd9c 100644
--- a/howto/maintain-git.html
+++ b/howto/maintain-git.html
@@ -1469,7 +1469,7 @@ $ git update-ref -d $mf/ai/topic</code></pre>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:49 PDT
+ 2022-08-18 14:11:39 PDT
</div>
</div>
</body>
diff --git a/howto/new-command.html b/howto/new-command.html
index 202d9a77d..55ac5b3ac 100644
--- a/howto/new-command.html
+++ b/howto/new-command.html
@@ -863,7 +863,7 @@ letter [PATCH 0/n].
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:46 PDT
+ 2022-08-18 14:11:37 PDT
</div>
</div>
</body>
diff --git a/howto/rebase-from-internal-branch.html b/howto/rebase-from-internal-branch.html
index 112ace3ca..f43efcf2d 100644
--- a/howto/rebase-from-internal-branch.html
+++ b/howto/rebase-from-internal-branch.html
@@ -895,7 +895,7 @@ the #1' commit.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:48 PDT
+ 2022-08-18 14:11:39 PDT
</div>
</div>
</body>
diff --git a/howto/rebuild-from-update-hook.html b/howto/rebuild-from-update-hook.html
index 34e9b24ca..19c2bfadd 100644
--- a/howto/rebuild-from-update-hook.html
+++ b/howto/rebuild-from-update-hook.html
@@ -847,7 +847,7 @@ This is still crude and does not protect against simultaneous
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:48 PDT
+ 2022-08-18 14:11:39 PDT
</div>
</div>
</body>
diff --git a/howto/recover-corrupted-blob-object.html b/howto/recover-corrupted-blob-object.html
index 5a2488e83..77c4c3699 100644
--- a/howto/recover-corrupted-blob-object.html
+++ b/howto/recover-corrupted-blob-object.html
@@ -880,7 +880,7 @@ thing.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:48 PDT
+ 2022-08-18 14:11:39 PDT
</div>
</div>
</body>
diff --git a/howto/recover-corrupted-object-harder.html b/howto/recover-corrupted-object-harder.html
index ee9a9cada..433d9ce27 100644
--- a/howto/recover-corrupted-object-harder.html
+++ b/howto/recover-corrupted-object-harder.html
@@ -793,7 +793,7 @@ corruption). But everything looked pretty reasonable.</p></div>
has the git packed object header, which is variable-length. We want to
strip that off so we can start playing with the zlib data directly. You
can either work your way through it manually (the format is described in
-<a href="../technical/pack-format.html">Documentation/technical/pack-format.txt</a>),
+<a href="../gitformat-pack.html">gitformat-pack(5)</a>),
or you can walk through it in a debugger. I did the latter, creating a
valid pack like:</p></div>
<div class="listingblock">
@@ -1189,7 +1189,7 @@ int main(int argc, char **argv)
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:48 PDT
+ 2022-08-18 14:11:39 PDT
</div>
</div>
</body>
diff --git a/howto/recover-corrupted-object-harder.txt b/howto/recover-corrupted-object-harder.txt
index 8994e2559..5efb4fe81 100644
--- a/howto/recover-corrupted-object-harder.txt
+++ b/howto/recover-corrupted-object-harder.txt
@@ -68,7 +68,7 @@ Note that the "object" file isn't fit for feeding straight to zlib; it
has the git packed object header, which is variable-length. We want to
strip that off so we can start playing with the zlib data directly. You
can either work your way through it manually (the format is described in
-link:../technical/pack-format.html[Documentation/technical/pack-format.txt]),
+linkgit:gitformat-pack[5]),
or you can walk through it in a debugger. I did the latter, creating a
valid pack like:
diff --git a/howto/revert-a-faulty-merge.html b/howto/revert-a-faulty-merge.html
index 1122c2ccd..439c068ad 100644
--- a/howto/revert-a-faulty-merge.html
+++ b/howto/revert-a-faulty-merge.html
@@ -1025,7 +1025,7 @@ P---o---o---M---x---x---W---x---M2
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:48 PDT
+ 2022-08-18 14:11:38 PDT
</div>
</div>
</body>
diff --git a/howto/revert-branch-rebase.html b/howto/revert-branch-rebase.html
index 6b3280cd6..540e80c41 100644
--- a/howto/revert-branch-rebase.html
+++ b/howto/revert-branch-rebase.html
@@ -907,7 +907,7 @@ Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:47 PDT
+ 2022-08-18 14:11:37 PDT
</div>
</div>
</body>
diff --git a/howto/separating-topic-branches.html b/howto/separating-topic-branches.html
index 721c5392b..a135545ca 100644
--- a/howto/separating-topic-branches.html
+++ b/howto/separating-topic-branches.html
@@ -841,7 +841,7 @@ o---o"master"</code></pre>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:48 PDT
+ 2022-08-18 14:11:38 PDT
</div>
</div>
</body>
diff --git a/howto/setup-git-server-over-http.html b/howto/setup-git-server-over-http.html
index 9f7b3c25d..6f00a2d74 100644
--- a/howto/setup-git-server-over-http.html
+++ b/howto/setup-git-server-over-http.html
@@ -1071,7 +1071,7 @@ help diagnosing the problem, but removes security checks.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:47 PDT
+ 2022-08-18 14:11:38 PDT
</div>
</div>
</body>
diff --git a/howto/update-hook-example.html b/howto/update-hook-example.html
index 94b06833c..f84af3dcf 100644
--- a/howto/update-hook-example.html
+++ b/howto/update-hook-example.html
@@ -930,7 +930,7 @@ that JC can make non-fast-forward pushes on it.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:47 PDT
+ 2022-08-18 14:11:38 PDT
</div>
</div>
</body>
diff --git a/howto/use-git-daemon.html b/howto/use-git-daemon.html
index f4e4a48a0..993e309a4 100644
--- a/howto/use-git-daemon.html
+++ b/howto/use-git-daemon.html
@@ -791,7 +791,7 @@ a good practice to put the paths after a "--" separator.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:47 PDT
+ 2022-08-18 14:11:38 PDT
</div>
</div>
</body>
diff --git a/howto/using-merge-subtree.html b/howto/using-merge-subtree.html
index 3e15aaea7..2d74fe0f4 100644
--- a/howto/using-merge-subtree.html
+++ b/howto/using-merge-subtree.html
@@ -848,7 +848,7 @@ Please note that if the other project merges from you, then it will
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:47 PDT
+ 2022-08-18 14:11:37 PDT
</div>
</div>
</body>
diff --git a/howto/using-signed-tag-in-pull-request.html b/howto/using-signed-tag-in-pull-request.html
index 8fdd9d234..9cad02bb1 100644
--- a/howto/using-signed-tag-in-pull-request.html
+++ b/howto/using-signed-tag-in-pull-request.html
@@ -952,7 +952,7 @@ as part of the merge commit.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-08-12 14:05:47 PDT
+ 2022-08-18 14:11:38 PDT
</div>
</div>
</body>
diff --git a/rerere-options.txt b/rerere-options.txt
new file mode 100644
index 000000000..c3321ddea
--- /dev/null
+++ b/rerere-options.txt
@@ -0,0 +1,9 @@
+--rerere-autoupdate::
+--no-rerere-autoupdate::
+ After the rerere mechanism reuses a recorded resolution on
+ the current conflict to update the files in the working
+ tree, allow it to also update the index with the result of
+ resolution. `--no-rerere-autoupdate` is a good way to
+ double-check what `rerere` did and catch potential
+ mismerges, before committing the result to the index with a
+ separate `git add`.
diff --git a/rev-list-options.txt b/rev-list-options.txt
index 195e74eec..bd08d1857 100644
--- a/rev-list-options.txt
+++ b/rev-list-options.txt
@@ -242,6 +242,7 @@ ifdef::git-rev-list[]
to `/dev/null` as the output does not have to be formatted.
--disk-usage::
+--disk-usage=human::
Suppress normal output; instead, print the sum of the bytes used
for on-disk storage by the selected commits or objects. This is
equivalent to piping the output into `git cat-file
@@ -249,6 +250,8 @@ ifdef::git-rev-list[]
faster (especially with `--use-bitmap-index`). See the `CAVEATS`
section in linkgit:git-cat-file[1] for the limitations of what
"on-disk storage" means.
+ With the optional value `human`, on-disk storage size is shown
+ in human-readable string(e.g. 12.24 Kib, 3.50 Mib).
endif::git-rev-list[]
--cherry-mark::
diff --git a/technical/api-simple-ipc.html b/technical/api-simple-ipc.html
index 7094be5ca..bd771786a 100644
--- a/technical/api-simple-ipc.html
+++ b/technical/api-simple-ipc.html
@@ -809,7 +809,7 @@ shutdown when idle or only upon explicit request.</p></div>
client and an optional response message from the server. Both the
client and server messages are unlimited in length and are terminated
with a flush packet.</p></div>
-<div class="paragraph"><p>The pkt-line routines (Documentation/technical/protocol-common.txt)
+<div class="paragraph"><p>The pkt-line routines (<a href="../gitprotocol-common.html">gitprotocol-common(5)</a>)
are used to simplify buffer management during message generation,
transmission, and reception. A flush packet is used to mark the end
of the message. This allows the sender to incrementally generate and
@@ -840,7 +840,7 @@ layer to focus on the application at hand.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2021-04-02 18:34:47 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/technical/api-simple-ipc.txt b/technical/api-simple-ipc.txt
index d79ad323e..d44ada98e 100644
--- a/technical/api-simple-ipc.txt
+++ b/technical/api-simple-ipc.txt
@@ -78,7 +78,7 @@ client and an optional response message from the server. Both the
client and server messages are unlimited in length and are terminated
with a flush packet.
-The pkt-line routines (Documentation/technical/protocol-common.txt)
+The pkt-line routines (linkgit:gitprotocol-common[5])
are used to simplify buffer management during message generation,
transmission, and reception. A flush packet is used to mark the end
of the message. This allows the sender to incrementally generate and
diff --git a/technical/bundle-uri.html b/technical/bundle-uri.html
new file mode 100644
index 000000000..4c392bcf1
--- /dev/null
+++ b/technical/bundle-uri.html
@@ -0,0 +1,1471 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 10.2.0" />
+<title>Bundle URIs</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>Bundle URIs</h1>
+</div>
+<div id="content">
+<div id="preamble">
+<div class="sectionbody">
+<div class="paragraph"><p>Git bundles are files that store a pack-file along with some extra metadata,
+including a set of refs and a (possibly empty) set of necessary commits. See
+<a href="../git-bundle.html">git-bundle(1)</a> and <a href="bundle-format.txt">the bundle format</a> for more
+information.</p></div>
+<div class="paragraph"><p>Bundle URIs are locations where Git can download one or more bundles in
+order to bootstrap the object database in advance of fetching the remaining
+objects from a remote.</p></div>
+<div class="paragraph"><p>One goal is to speed up clones and fetches for users with poor network
+connectivity to the origin server. Another benefit is to allow heavy users,
+such as CI build farms, to use local resources for the majority of Git data
+and thereby reducing the load on the origin server.</p></div>
+<div class="paragraph"><p>To enable the bundle URI feature, users can specify a bundle URI using
+command-line options or the origin server can advertise one or more URIs
+via a protocol v2 capability.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_design_goals">Design Goals</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The bundle URI standard aims to be flexible enough to satisfy multiple
+workloads. The bundle provider and the Git client have several choices in
+how they create and consume bundle URIs.</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Bundles can have whatever name the server desires. This name could refer
+ to immutable data by using a hash of the bundle contents. However, this
+ means that a new URI will be needed after every update of the content.
+ This might be acceptable if the server is advertising the URI (and the
+ server is aware of new bundles being generated) but would not be
+ ergonomic for users using the command line option.
+</p>
+</li>
+<li>
+<p>
+The bundles could be organized specifically for bootstrapping full
+ clones, but could also be organized with the intention of bootstrapping
+ incremental fetches. The bundle provider must decide on one of several
+ organization schemes to minimize client downloads during incremental
+ fetches, but the Git client can also choose whether to use bundles for
+ either of these operations.
+</p>
+</li>
+<li>
+<p>
+The bundle provider can choose to support full clones, partial clones,
+ or both. The client can detect which bundles are appropriate for the
+ repository&#8217;s partial clone filter, if any.
+</p>
+</li>
+<li>
+<p>
+The bundle provider can use a single bundle (for clones only), or a
+ list of bundles. When using a list of bundles, the provider can specify
+ whether or not the client needs <em>all</em> of the bundle URIs for a full
+ clone, or if <em>any</em> one of the bundle URIs is sufficient. This allows the
+ bundle provider to use different URIs for different geographies.
+</p>
+</li>
+<li>
+<p>
+The bundle provider can organize the bundles using heuristics, such as
+ creation tokens, to help the client prevent downloading bundles it does
+ not need. When the bundle provider does not provide these heuristics,
+ the client can use optimizations to minimize how much of the data is
+ downloaded.
+</p>
+</li>
+<li>
+<p>
+The bundle provider does not need to be associated with the Git server.
+ The client can choose to use the bundle provider without it being
+ advertised by the Git server.
+</p>
+</li>
+<li>
+<p>
+The client can choose to discover bundle providers that are advertised
+ by the Git server. This could happen during <code>git clone</code>, during
+ <code>git fetch</code>, both, or neither. The user can choose which combination
+ works best for them.
+</p>
+</li>
+<li>
+<p>
+The client can choose to configure a bundle provider manually at any
+ time. The client can also choose to specify a bundle provider manually
+ as a command-line option to <code>git clone</code>.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>Each repository is different and every Git server has different needs.
+Hopefully the bundle URI feature is flexible enough to satisfy all needs.
+If not, then the feature can be extended through its versioning mechanism.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_server_requirements">Server requirements</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>To provide a server-side implementation of bundle servers, no other parts
+of the Git protocol are required. This allows server maintainers to use
+static content solutions such as CDNs in order to serve the bundle files.</p></div>
+<div class="paragraph"><p>At the current scope of the bundle URI feature, all URIs are expected to
+be HTTP(S) URLs where content is downloaded to a local file using a <code>GET</code>
+request to that URL. The server could include authentication requirements
+to those requests with the aim of triggering the configured credential
+helper for secure access. (Future extensions could use "file://" URIs or
+SSH URIs.)</p></div>
+<div class="paragraph"><p>Assuming a <code>200 OK</code> response from the server, the content at the URL is
+inspected. First, Git attempts to parse the file as a bundle file of
+version 2 or higher. If the file is not a bundle, then the file is parsed
+as a plain-text file using Git&#8217;s config parser. The key-value pairs in
+that config file are expected to describe a list of bundle URIs. If
+neither of these parse attempts succeed, then Git will report an error to
+the user that the bundle URI provided erroneous data.</p></div>
+<div class="paragraph"><p>Any other data provided by the server is considered erroneous.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_bundle_lists">Bundle Lists</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Git server can advertise bundle URIs using a set of <code>key=value</code> pairs.
+A bundle URI can also serve a plain-text file in the Git config format
+containing these same <code>key=value</code> pairs. In both cases, we consider this
+to be a <em>bundle list</em>. The pairs specify information about the bundles
+that the client can use to make decisions for which bundles to download
+and which to ignore.</p></div>
+<div class="paragraph"><p>A few keys focus on properties of the list itself.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+bundle.version
+</dt>
+<dd>
+<p>
+ (Required) This value provides a version number for the bundle
+ list. If a future Git change enables a feature that needs the Git
+ client to react to a new key in the bundle list file, then this version
+ will increment. The only current version number is 1, and if any other
+ value is specified then Git will fail to use this file.
+</p>
+</dd>
+<dt class="hdlist1">
+bundle.mode
+</dt>
+<dd>
+<p>
+ (Required) This value has one of two values: <code>all</code> and <code>any</code>. When <code>all</code>
+ is specified, then the client should expect to need all of the listed
+ bundle URIs that match their repository&#8217;s requirements. When <code>any</code> is
+ specified, then the client should expect that any one of the bundle URIs
+ that match their repository&#8217;s requirements will suffice. Typically, the
+ <code>any</code> option is used to list a number of different bundle servers
+ located in different geographies.
+</p>
+</dd>
+<dt class="hdlist1">
+bundle.heuristic
+</dt>
+<dd>
+<p>
+ If this string-valued key exists, then the bundle list is designed to
+ work well with incremental <code>git fetch</code> commands. The heuristic signals
+ that there are additional keys available for each bundle that help
+ determine which subset of bundles the client should download. The only
+ heuristic currently planned is <code>creationToken</code>.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>The remaining keys include an <code>&lt;id&gt;</code> segment which is a server-designated
+name for each available bundle. The <code>&lt;id&gt;</code> must contain only alphanumeric
+and <code>-</code> characters.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+bundle.&lt;id&gt;.uri
+</dt>
+<dd>
+<p>
+ (Required) This string value is the URI for downloading bundle <code>&lt;id&gt;</code>.
+ If the URI begins with a protocol (<code>http://</code> or <code>https://</code>) then the URI
+ is absolute. Otherwise, the URI is interpreted as relative to the URI
+ used for the bundle list. If the URI begins with <code>/</code>, then that relative
+ path is relative to the domain name used for the bundle list. (This use
+ of relative paths is intended to make it easier to distribute a set of
+ bundles across a large number of servers or CDNs with different domain
+ names.)
+</p>
+</dd>
+<dt class="hdlist1">
+bundle.&lt;id&gt;.filter
+</dt>
+<dd>
+<p>
+ This string value represents an object filter that should also appear in
+ the header of this bundle. The server uses this value to differentiate
+ different kinds of bundles from which the client can choose those that
+ match their object filters.
+</p>
+</dd>
+<dt class="hdlist1">
+bundle.&lt;id&gt;.creationToken
+</dt>
+<dd>
+<p>
+ This value is a nonnegative 64-bit integer used for sorting the bundles
+ the list. This is used to download a subset of bundles during a fetch
+ when <code>bundle.heuristic=creationToken</code>.
+</p>
+</dd>
+<dt class="hdlist1">
+bundle.&lt;id&gt;.location
+</dt>
+<dd>
+<p>
+ This string value advertises a real-world location from where the bundle
+ URI is served. This can be used to present the user with an option for
+ which bundle URI to use or simply as an informative indicator of which
+ bundle URI was selected by Git. This is only valuable when
+ <code>bundle.mode</code> is <code>any</code>.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>Here is an example bundle list using the Git config format:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle]
+ version = 1
+ mode = all
+ heuristic = creationToken</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "2022-02-09-1644442601-daily"]
+ uri = https://bundles.example.com/git/git/2022-02-09-1644442601-daily.bundle
+ creationToken = 1644442601</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "2022-02-02-1643842562"]
+ uri = https://bundles.example.com/git/git/2022-02-02-1643842562.bundle
+ creationToken = 1643842562</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "2022-02-09-1644442631-daily-blobless"]
+ uri = 2022-02-09-1644442631-daily-blobless.bundle
+ creationToken = 1644442631
+ filter = blob:none</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "2022-02-02-1643842568-blobless"]
+ uri = /git/git/2022-02-02-1643842568-blobless.bundle
+ creationToken = 1643842568
+ filter = blob:none</code></pre>
+</div></div>
+<div class="paragraph"><p>This example uses <code>bundle.mode=all</code> as well as the
+<code>bundle.&lt;id&gt;.creationToken</code> heuristic. It also uses the <code>bundle.&lt;id&gt;.filter</code>
+options to present two parallel sets of bundles: one for full clones and
+another for blobless partial clones.</p></div>
+<div class="paragraph"><p>Suppose that this bundle list was found at the URI
+<code>https://bundles.example.com/git/git/</code> and so the two blobless bundles have
+the following fully-expanded URIs:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+<code>https://bundles.example.com/git/git/2022-02-09-1644442631-daily-blobless.bundle</code>
+</p>
+</li>
+<li>
+<p>
+<code>https://bundles.example.com/git/git/2022-02-02-1643842568-blobless.bundle</code>
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_advertising_bundle_uris">Advertising Bundle URIs</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If a user knows a bundle URI for the repository they are cloning, then
+they can specify that URI manually through a command-line option. However,
+a Git host may want to advertise bundle URIs during the clone operation,
+helping users unaware of the feature.</p></div>
+<div class="paragraph"><p>The only thing required for this feature is that the server can advertise
+one or more bundle URIs. This advertisement takes the form of a new
+protocol v2 capability specifically for discovering bundle URIs.</p></div>
+<div class="paragraph"><p>The client could choose an arbitrary bundle URI as an option <em>or</em> select
+the URI with best performance by some exploratory checks. It is up to the
+bundle provider to decide if having multiple URIs is preferable to a
+single URI that is geodistributed through server-side infrastructure.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_cloning_with_bundle_uris">Cloning with Bundle URIs</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The primary need for bundle URIs is to speed up clones. The Git client
+will interact with bundle URIs according to the following flow:</p></div>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+The user specifies a bundle URI with the <code>--bundle-uri</code> command-line
+ option <em>or</em> the client discovers a bundle list advertised by the
+ Git server.
+</p>
+</li>
+<li>
+<p>
+If the downloaded data from a bundle URI is a bundle, then the client
+ inspects the bundle headers to check that the prerequisite commit OIDs
+ are present in the client repository. If some are missing, then the
+ client delays unbundling until other bundles have been unbundled,
+ making those OIDs present. When all required OIDs are present, the
+ client unbundles that data using a refspec. The default refspec is
+ <code>+refs/heads/*:refs/bundles/*</code>, but this can be configured. These refs
+ are stored so that later <code>git fetch</code> negotiations can communicate the
+ bundled refs as <code>have`s, reducing the size of the fetch over the Git
+ protocol. To allow pruning refs from this ref namespace, Git may
+ introduce a numbered namespace (such as `refs/bundles/&lt;i&gt;/*</code>) such that
+ stale bundle refs can be deleted.
+</p>
+</li>
+<li>
+<p>
+If the file is instead a bundle list, then the client inspects the
+ <code>bundle.mode</code> to see if the list is of the <code>all</code> or <code>any</code> form.
+</p>
+<div class="olist loweralpha"><ol class="loweralpha">
+<li>
+<p>
+If <code>bundle.mode=all</code>, then the client considers all bundle
+ URIs. The list is reduced based on the <code>bundle.&lt;id&gt;.filter</code> options
+ matching the client repository&#8217;s partial clone filter. Then, all
+ bundle URIs are requested. If the <code>bundle.&lt;id&gt;.creationToken</code>
+ heuristic is provided, then the bundles are downloaded in decreasing
+ order by the creation token, stopping when a bundle has all required
+ OIDs. The bundles can then be unbundled in increasing creation token
+ order. The client stores the latest creation token as a heuristic
+ for avoiding future downloads if the bundle list does not advertise
+ bundles with larger creation tokens.
+</p>
+</li>
+<li>
+<p>
+If <code>bundle.mode=any</code>, then the client can choose any one of the
+ bundle URIs to inspect. The client can use a variety of ways to
+ choose among these URIs. The client can also fallback to another URI
+ if the initial choice fails to return a result.
+</p>
+</li>
+</ol></div>
+</li>
+</ol></div>
+<div class="paragraph"><p>Note that during a clone we expect that all bundles will be required, and
+heuristics such as <code>bundle.&lt;uri&gt;.creationToken</code> can be used to download
+bundles in chronological order or in parallel.</p></div>
+<div class="paragraph"><p>If a given bundle URI is a bundle list with a <code>bundle.heuristic</code>
+value, then the client can choose to store that URI as its chosen bundle
+URI. The client can then navigate directly to that URI during later <code>git
+fetch</code> calls.</p></div>
+<div class="paragraph"><p>When downloading bundle URIs, the client can choose to inspect the initial
+content before committing to downloading the entire content. This may
+provide enough information to determine if the URI is a bundle list or
+a bundle. In the case of a bundle, the client may inspect the bundle
+header to determine that all advertised tips are already in the client
+repository and cancel the remaining download.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_fetching_with_bundle_uris">Fetching with Bundle URIs</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>When the client fetches new data, it can decide to fetch from bundle
+servers before fetching from the origin remote. This could be done via a
+command-line option, but it is more likely useful to use a config value
+such as the one specified during the clone.</p></div>
+<div class="paragraph"><p>The fetch operation follows the same procedure to download bundles from a
+bundle list (although we do <em>not</em> want to use parallel downloads here). We
+expect that the process will end when all prerequisite commit OIDs in a
+thin bundle are already in the object database.</p></div>
+<div class="paragraph"><p>When using the <code>creationToken</code> heuristic, the client can avoid downloading
+any bundles if their creation tokenss are not larger than the stored
+creation token. After fetching new bundles, Git updates this local
+creation token.</p></div>
+<div class="paragraph"><p>If the bundle provider does not provide a heuristic, then the client
+should attempt to inspect the bundle headers before downloading the full
+bundle data in case the bundle tips already exist in the client
+repository.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_error_conditions">Error Conditions</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>If the Git client discovers something unexpected while downloading
+information according to a bundle URI or the bundle list found at that
+location, then Git can ignore that data and continue as if it was not
+given a bundle URI. The remote Git server is the ultimate source of truth,
+not the bundle URI.</p></div>
+<div class="paragraph"><p>Here are a few example error conditions:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+The client fails to connect with a server at the given URI or a connection
+ is lost without any chance to recover.
+</p>
+</li>
+<li>
+<p>
+The client receives a 400-level response (such as <code>404 Not Found</code> or
+ <code>401 Not Authorized</code>). The client should use the credential helper to
+ find and provide a credential for the URI, but match the semantics of
+ Git&#8217;s other HTTP protocols in terms of handling specific 400-level
+ errors.
+</p>
+</li>
+<li>
+<p>
+The server reports any other failure reponse.
+</p>
+</li>
+<li>
+<p>
+The client receives data that is not parsable as a bundle or bundle list.
+</p>
+</li>
+<li>
+<p>
+A bundle includes a filter that does not match expectations.
+</p>
+</li>
+<li>
+<p>
+The client cannot unbundle the bundles because the prerequisite commit OIDs
+ are not in the object database and there are no more bundles to download.
+</p>
+</li>
+</ul></div>
+<div class="paragraph"><p>There are also situations that could be seen as wasteful, but are not
+error conditions:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+The downloaded bundles contain more information than is requested by
+ the clone or fetch request. A primary example is if the user requests
+ a clone with <code>--single-branch</code> but downloads bundles that store every
+ reachable commit from all <code>refs/heads/*</code> references. This might be
+ initially wasteful, but perhaps these objects will become reachable by
+ a later ref update that the client cares about.
+</p>
+</li>
+<li>
+<p>
+A bundle download during a <code>git fetch</code> contains objects already in the
+ object database. This is probably unavoidable if we are using bundles
+ for fetches, since the client will almost always be slightly ahead of
+ the bundle servers after performing its "catch-up" fetch to the remote
+ server. This extra work is most wasteful when the client is fetching
+ much more frequently than the server is computing bundles, such as if
+ the client is using hourly prefetches with background maintenance, but
+ the server is computing bundles weekly. For this reason, the client
+ should not use bundle URIs for fetch unless the server has explicitly
+ recommended it through a <code>bundle.heuristic</code> value.
+</p>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_example_bundle_provider_organization">Example Bundle Provider organization</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The bundle URI feature is intentionally designed to be flexible to
+different ways a bundle provider wants to organize the object data.
+However, it can be helpful to have a complete organization model described
+here so providers can start from that base.</p></div>
+<div class="paragraph"><p>This example organization is a simplified model of what is used by the
+GVFS Cache Servers (see section near the end of this document) which have
+been beneficial in speeding up clones and fetches for very large
+repositories, although using extra software outside of Git.</p></div>
+<div class="paragraph"><p>The bundle provider deploys servers across multiple geographies. Each
+server manages its own bundle set. The server can track a number of Git
+repositories, but provides a bundle list for each based on a pattern. For
+example, when mirroring a repository at <code>https://&lt;domain&gt;/&lt;org&gt;/&lt;repo&gt;</code>
+the bundle server could have its bundle list available at
+<code>https://&lt;server-url&gt;/&lt;domain&gt;/&lt;org&gt;/&lt;repo&gt;</code>. The origin Git server can
+list all of these servers under the "any" mode:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle]
+ version = 1
+ mode = any</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "eastus"]
+ uri = https://eastus.example.com/&lt;domain&gt;/&lt;org&gt;/&lt;repo&gt;</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "europe"]
+ uri = https://europe.example.com/&lt;domain&gt;/&lt;org&gt;/&lt;repo&gt;</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "apac"]
+ uri = https://apac.example.com/&lt;domain&gt;/&lt;org&gt;/&lt;repo&gt;</code></pre>
+</div></div>
+<div class="paragraph"><p>This "list of lists" is static and only changes if a bundle server is
+added or removed.</p></div>
+<div class="paragraph"><p>Each bundle server manages its own set of bundles. The initial bundle list
+contains only a single bundle, containing all of the objects received from
+cloning the repository from the origin server. The list uses the
+<code>creationToken</code> heuristic and a <code>creationToken</code> is made for the bundle
+based on the server&#8217;s timestamp.</p></div>
+<div class="paragraph"><p>The bundle server runs regularly-scheduled updates for the bundle list,
+such as once a day. During this task, the server fetches the latest
+contents from the origin server and generates a bundle containing the
+objects reachable from the latest origin refs, but not contained in a
+previously-computed bundle. This bundle is added to the list, with care
+that the <code>creationToken</code> is strictly greater than the previous maximum
+<code>creationToken</code>.</p></div>
+<div class="paragraph"><p>When the bundle list grows too large, say more than 30 bundles, then the
+oldest "<em>N</em> minus 30" bundles are combined into a single bundle. This
+bundle&#8217;s <code>creationToken</code> is equal to the maximum <code>creationToken</code> among the
+merged bundles.</p></div>
+<div class="paragraph"><p>An example bundle list is provided here, although it only has two daily
+bundles and not a full list of 30:</p></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle]
+ version = 1
+ mode = all
+ heuristic = creationToken</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "2022-02-13-1644770820-daily"]
+ uri = https://eastus.example.com/&lt;domain&gt;/&lt;org&gt;/&lt;repo&gt;/2022-02-09-1644770820-daily.bundle
+ creationToken = 1644770820</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "2022-02-09-1644442601-daily"]
+ uri = https://eastus.example.com/&lt;domain&gt;/&lt;org&gt;/&lt;repo&gt;/2022-02-09-1644442601-daily.bundle
+ creationToken = 1644442601</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>[bundle "2022-02-02-1643842562"]
+ uri = https://eastus.example.com/&lt;domain&gt;/&lt;org&gt;/&lt;repo&gt;/2022-02-02-1643842562.bundle
+ creationToken = 1643842562</code></pre>
+</div></div>
+<div class="paragraph"><p>To avoid storing and serving object data in perpetuity despite becoming
+unreachable in the origin server, this bundle merge can be more careful.
+Instead of taking an absolute union of the old bundles, instead the bundle
+can be created by looking at the newer bundles and ensuring that their
+necessary commits are all available in this merged bundle (or in another
+one of the newer bundles). This allows "expiring" object data that is not
+being used by new commits in this window of time. That data could be
+reintroduced by a later push.</p></div>
+<div class="paragraph"><p>The intention of this data organization has two main goals. First, initial
+clones of the repository become faster by downloading precomputed object
+data from a closer source. Second, <code>git fetch</code> commands can be faster,
+especially if the client has not fetched for a few days. However, if a
+client does not fetch for 30 days, then the bundle list organization would
+cause redownloading a large amount of object data.</p></div>
+<div class="paragraph"><p>One way to make this organization more useful to users who fetch frequently
+is to have more frequent bundle creation. For example, bundles could be
+created every hour, and then once a day those "hourly" bundles could be
+merged into a "daily" bundle. The daily bundles are merged into the
+oldest bundle after 30 days.</p></div>
+<div class="paragraph"><p>It is recommened that this bundle strategy is repeated with the <code>blob:none</code>
+filter if clients of this repository are expecting to use blobless partial
+clones. This list of blobless bundles stays in the same list as the full
+bundles, but uses the <code>bundle.&lt;id&gt;.filter</code> key to separate the two groups.
+For very large repositories, the bundle provider may want to <em>only</em> provide
+blobless bundles.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_implementation_plan">Implementation Plan</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This design document is being submitted on its own as an aspirational
+document, with the goal of implementing all of the mentioned client
+features over the course of several patch series. Here is a potential
+outline for submitting these features:</p></div>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+Integrate bundle URIs into <code>git clone</code> with a <code>--bundle-uri</code> option.
+ This will include a new <code>git fetch --bundle-uri</code> mode for use as the
+ implementation underneath <code>git clone</code>. The initial version here will
+ expect a single bundle at the given URI.
+</p>
+</li>
+<li>
+<p>
+Implement the ability to parse a bundle list from a bundle URI and
+ update the <code>git fetch --bundle-uri</code> logic to properly distinguish
+ between <code>bundle.mode</code> options. Specifically design the feature so
+ that the config format parsing feeds a list of key-value pairs into the
+ bundle list logic.
+</p>
+</li>
+<li>
+<p>
+Create the <code>bundle-uri</code> protocol v2 command so Git servers can advertise
+ bundle URIs using the key-value pairs. Plug into the existing key-value
+ input to the bundle list logic. Allow <code>git clone</code> to discover these
+ bundle URIs and bootstrap the client repository from the bundle data.
+ (This choice is an opt-in via a config option and a command-line
+ option.)
+</p>
+</li>
+<li>
+<p>
+Allow the client to understand the <code>bundle.flag=forFetch</code> configuration
+ and the <code>bundle.&lt;id&gt;.creationToken</code> heuristic. When <code>git clone</code>
+ discovers a bundle URI with <code>bundle.flag=forFetch</code>, it configures the
+ client repository to check that bundle URI during later <code>git fetch &lt;remote&gt;</code>
+ commands.
+</p>
+</li>
+<li>
+<p>
+Allow clients to discover bundle URIs during <code>git fetch</code> and configure
+ a bundle URI for later fetches if <code>bundle.flag=forFetch</code>.
+</p>
+</li>
+<li>
+<p>
+Implement the "inspect headers" heuristic to reduce data downloads when
+ the <code>bundle.&lt;id&gt;.creationToken</code> heuristic is not available.
+</p>
+</li>
+</ol></div>
+<div class="paragraph"><p>As these features are reviewed, this plan might be updated. We also expect
+that new designs will be discovered and implemented as this feature
+matures and becomes used in real-world scenarios.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_related_work_packfile_uris">Related Work: Packfile URIs</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Git protocol already has a capability where the Git server can list
+a set of URLs along with the packfile response when serving a client
+request. The client is then expected to download the packfiles at those
+locations in order to have a complete understanding of the response.</p></div>
+<div class="paragraph"><p>This mechanism is used by the Gerrit server (implemented with JGit) and
+has been effective at reducing CPU load and improving user performance for
+clones.</p></div>
+<div class="paragraph"><p>A major downside to this mechanism is that the origin server needs to know
+<em>exactly</em> what is in those packfiles, and the packfiles need to be available
+to the user for some time after the server has responded. This coupling
+between the origin and the packfile data is difficult to manage.</p></div>
+<div class="paragraph"><p>Further, this implementation is extremely hard to make work with fetches.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_related_work_gvfs_cache_servers">Related Work: GVFS Cache Servers</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The GVFS Protocol [2] is a set of HTTP endpoints designed independently of
+the Git project before Git&#8217;s partial clone was created. One feature of this
+protocol is the idea of a "cache server" which can be colocated with build
+machines or developer offices to transfer Git data without overloading the
+central server.</p></div>
+<div class="paragraph"><p>The endpoint that VFS for Git is famous for is the <code>GET /gvfs/objects/{oid}</code>
+endpoint, which allows downloading an object on-demand. This is a critical
+piece of the filesystem virtualization of that product.</p></div>
+<div class="paragraph"><p>However, a more subtle need is the <code>GET /gvfs/prefetch?lastPackTimestamp=&lt;t&gt;</code>
+endpoint. Given an optional timestamp, the cache server responds with a list
+of precomputed packfiles containing the commits and trees that were introduced
+in those time intervals.</p></div>
+<div class="paragraph"><p>The cache server computes these "prefetch" packfiles using the following
+strategy:</p></div>
+<div class="olist arabic"><ol class="arabic">
+<li>
+<p>
+Every hour, an "hourly" pack is generated with a given timestamp.
+</p>
+</li>
+<li>
+<p>
+Nightly, the previous 24 hourly packs are rolled up into a "daily" pack.
+</p>
+</li>
+<li>
+<p>
+Nightly, all prefetch packs more than 30 days old are rolled up into
+ one pack.
+</p>
+</li>
+</ol></div>
+<div class="paragraph"><p>When a user runs <code>gvfs clone</code> or <code>scalar clone</code> against a repo with cache
+servers, the client requests all prefetch packfiles, which is at most
+<code>24 + 30 + 1</code> packfiles downloading only commits and trees. The client
+then follows with a request to the origin server for the references, and
+attempts to checkout that tip reference. (There is an extra endpoint that
+helps get all reachable trees from a given commit, in case that commit
+was not already in a prefetch packfile.)</p></div>
+<div class="paragraph"><p>During a <code>git fetch</code>, a hook requests the prefetch endpoint using the
+most-recent timestamp from a previously-downloaded prefetch packfile.
+Only the list of packfiles with later timestamps are downloaded. Most
+users fetch hourly, so they get at most one hourly prefetch pack. Users
+whose machines have been off or otherwise have not fetched in over 30 days
+might redownload all prefetch packfiles. This is rare.</p></div>
+<div class="paragraph"><p>It is important to note that the clients always contact the origin server
+for the refs advertisement, so the refs are frequently "ahead" of the
+prefetched pack data. The missing objects are downloaded on-demand using
+the <code>GET gvfs/objects/{oid}</code> requests, when needed by a command such as
+<code>git checkout</code> or <code>git log</code>. Some Git optimizations disable checks that
+would cause these on-demand downloads to be too aggressive.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">See Also</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>[1] <a href="https://lore.kernel.org/git/RFC-cover-00.13-0000000000-20210805T150534Z-avarab@gmail.com/">https://lore.kernel.org/git/RFC-cover-00.13-0000000000-20210805T150534Z-avarab@gmail.com/</a>
+ An earlier RFC for a bundle URI feature.</p></div>
+<div class="paragraph"><p>[2] <a href="https://github.com/microsoft/VFSForGit/blob/master/Protocol.md">https://github.com/microsoft/VFSForGit/blob/master/Protocol.md</a>
+ The GVFS Protocol</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2022-08-18 14:11:07 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/technical/bundle-uri.txt b/technical/bundle-uri.txt
new file mode 100644
index 000000000..c25c42378
--- /dev/null
+++ b/technical/bundle-uri.txt
@@ -0,0 +1,573 @@
+Bundle URIs
+===========
+
+Git bundles are files that store a pack-file along with some extra metadata,
+including a set of refs and a (possibly empty) set of necessary commits. See
+linkgit:git-bundle[1] and link:bundle-format.txt[the bundle format] for more
+information.
+
+Bundle URIs are locations where Git can download one or more bundles in
+order to bootstrap the object database in advance of fetching the remaining
+objects from a remote.
+
+One goal is to speed up clones and fetches for users with poor network
+connectivity to the origin server. Another benefit is to allow heavy users,
+such as CI build farms, to use local resources for the majority of Git data
+and thereby reducing the load on the origin server.
+
+To enable the bundle URI feature, users can specify a bundle URI using
+command-line options or the origin server can advertise one or more URIs
+via a protocol v2 capability.
+
+Design Goals
+------------
+
+The bundle URI standard aims to be flexible enough to satisfy multiple
+workloads. The bundle provider and the Git client have several choices in
+how they create and consume bundle URIs.
+
+* Bundles can have whatever name the server desires. This name could refer
+ to immutable data by using a hash of the bundle contents. However, this
+ means that a new URI will be needed after every update of the content.
+ This might be acceptable if the server is advertising the URI (and the
+ server is aware of new bundles being generated) but would not be
+ ergonomic for users using the command line option.
+
+* The bundles could be organized specifically for bootstrapping full
+ clones, but could also be organized with the intention of bootstrapping
+ incremental fetches. The bundle provider must decide on one of several
+ organization schemes to minimize client downloads during incremental
+ fetches, but the Git client can also choose whether to use bundles for
+ either of these operations.
+
+* The bundle provider can choose to support full clones, partial clones,
+ or both. The client can detect which bundles are appropriate for the
+ repository's partial clone filter, if any.
+
+* The bundle provider can use a single bundle (for clones only), or a
+ list of bundles. When using a list of bundles, the provider can specify
+ whether or not the client needs _all_ of the bundle URIs for a full
+ clone, or if _any_ one of the bundle URIs is sufficient. This allows the
+ bundle provider to use different URIs for different geographies.
+
+* The bundle provider can organize the bundles using heuristics, such as
+ creation tokens, to help the client prevent downloading bundles it does
+ not need. When the bundle provider does not provide these heuristics,
+ the client can use optimizations to minimize how much of the data is
+ downloaded.
+
+* The bundle provider does not need to be associated with the Git server.
+ The client can choose to use the bundle provider without it being
+ advertised by the Git server.
+
+* The client can choose to discover bundle providers that are advertised
+ by the Git server. This could happen during `git clone`, during
+ `git fetch`, both, or neither. The user can choose which combination
+ works best for them.
+
+* The client can choose to configure a bundle provider manually at any
+ time. The client can also choose to specify a bundle provider manually
+ as a command-line option to `git clone`.
+
+Each repository is different and every Git server has different needs.
+Hopefully the bundle URI feature is flexible enough to satisfy all needs.
+If not, then the feature can be extended through its versioning mechanism.
+
+Server requirements
+-------------------
+
+To provide a server-side implementation of bundle servers, no other parts
+of the Git protocol are required. This allows server maintainers to use
+static content solutions such as CDNs in order to serve the bundle files.
+
+At the current scope of the bundle URI feature, all URIs are expected to
+be HTTP(S) URLs where content is downloaded to a local file using a `GET`
+request to that URL. The server could include authentication requirements
+to those requests with the aim of triggering the configured credential
+helper for secure access. (Future extensions could use "file://" URIs or
+SSH URIs.)
+
+Assuming a `200 OK` response from the server, the content at the URL is
+inspected. First, Git attempts to parse the file as a bundle file of
+version 2 or higher. If the file is not a bundle, then the file is parsed
+as a plain-text file using Git's config parser. The key-value pairs in
+that config file are expected to describe a list of bundle URIs. If
+neither of these parse attempts succeed, then Git will report an error to
+the user that the bundle URI provided erroneous data.
+
+Any other data provided by the server is considered erroneous.
+
+Bundle Lists
+------------
+
+The Git server can advertise bundle URIs using a set of `key=value` pairs.
+A bundle URI can also serve a plain-text file in the Git config format
+containing these same `key=value` pairs. In both cases, we consider this
+to be a _bundle list_. The pairs specify information about the bundles
+that the client can use to make decisions for which bundles to download
+and which to ignore.
+
+A few keys focus on properties of the list itself.
+
+bundle.version::
+ (Required) This value provides a version number for the bundle
+ list. If a future Git change enables a feature that needs the Git
+ client to react to a new key in the bundle list file, then this version
+ will increment. The only current version number is 1, and if any other
+ value is specified then Git will fail to use this file.
+
+bundle.mode::
+ (Required) This value has one of two values: `all` and `any`. When `all`
+ is specified, then the client should expect to need all of the listed
+ bundle URIs that match their repository's requirements. When `any` is
+ specified, then the client should expect that any one of the bundle URIs
+ that match their repository's requirements will suffice. Typically, the
+ `any` option is used to list a number of different bundle servers
+ located in different geographies.
+
+bundle.heuristic::
+ If this string-valued key exists, then the bundle list is designed to
+ work well with incremental `git fetch` commands. The heuristic signals
+ that there are additional keys available for each bundle that help
+ determine which subset of bundles the client should download. The only
+ heuristic currently planned is `creationToken`.
+
+The remaining keys include an `<id>` segment which is a server-designated
+name for each available bundle. The `<id>` must contain only alphanumeric
+and `-` characters.
+
+bundle.<id>.uri::
+ (Required) This string value is the URI for downloading bundle `<id>`.
+ If the URI begins with a protocol (`http://` or `https://`) then the URI
+ is absolute. Otherwise, the URI is interpreted as relative to the URI
+ used for the bundle list. If the URI begins with `/`, then that relative
+ path is relative to the domain name used for the bundle list. (This use
+ of relative paths is intended to make it easier to distribute a set of
+ bundles across a large number of servers or CDNs with different domain
+ names.)
+
+bundle.<id>.filter::
+ This string value represents an object filter that should also appear in
+ the header of this bundle. The server uses this value to differentiate
+ different kinds of bundles from which the client can choose those that
+ match their object filters.
+
+bundle.<id>.creationToken::
+ This value is a nonnegative 64-bit integer used for sorting the bundles
+ the list. This is used to download a subset of bundles during a fetch
+ when `bundle.heuristic=creationToken`.
+
+bundle.<id>.location::
+ This string value advertises a real-world location from where the bundle
+ URI is served. This can be used to present the user with an option for
+ which bundle URI to use or simply as an informative indicator of which
+ bundle URI was selected by Git. This is only valuable when
+ `bundle.mode` is `any`.
+
+Here is an example bundle list using the Git config format:
+
+ [bundle]
+ version = 1
+ mode = all
+ heuristic = creationToken
+
+ [bundle "2022-02-09-1644442601-daily"]
+ uri = https://bundles.example.com/git/git/2022-02-09-1644442601-daily.bundle
+ creationToken = 1644442601
+
+ [bundle "2022-02-02-1643842562"]
+ uri = https://bundles.example.com/git/git/2022-02-02-1643842562.bundle
+ creationToken = 1643842562
+
+ [bundle "2022-02-09-1644442631-daily-blobless"]
+ uri = 2022-02-09-1644442631-daily-blobless.bundle
+ creationToken = 1644442631
+ filter = blob:none
+
+ [bundle "2022-02-02-1643842568-blobless"]
+ uri = /git/git/2022-02-02-1643842568-blobless.bundle
+ creationToken = 1643842568
+ filter = blob:none
+
+This example uses `bundle.mode=all` as well as the
+`bundle.<id>.creationToken` heuristic. It also uses the `bundle.<id>.filter`
+options to present two parallel sets of bundles: one for full clones and
+another for blobless partial clones.
+
+Suppose that this bundle list was found at the URI
+`https://bundles.example.com/git/git/` and so the two blobless bundles have
+the following fully-expanded URIs:
+
+* `https://bundles.example.com/git/git/2022-02-09-1644442631-daily-blobless.bundle`
+* `https://bundles.example.com/git/git/2022-02-02-1643842568-blobless.bundle`
+
+Advertising Bundle URIs
+-----------------------
+
+If a user knows a bundle URI for the repository they are cloning, then
+they can specify that URI manually through a command-line option. However,
+a Git host may want to advertise bundle URIs during the clone operation,
+helping users unaware of the feature.
+
+The only thing required for this feature is that the server can advertise
+one or more bundle URIs. This advertisement takes the form of a new
+protocol v2 capability specifically for discovering bundle URIs.
+
+The client could choose an arbitrary bundle URI as an option _or_ select
+the URI with best performance by some exploratory checks. It is up to the
+bundle provider to decide if having multiple URIs is preferable to a
+single URI that is geodistributed through server-side infrastructure.
+
+Cloning with Bundle URIs
+------------------------
+
+The primary need for bundle URIs is to speed up clones. The Git client
+will interact with bundle URIs according to the following flow:
+
+1. The user specifies a bundle URI with the `--bundle-uri` command-line
+ option _or_ the client discovers a bundle list advertised by the
+ Git server.
+
+2. If the downloaded data from a bundle URI is a bundle, then the client
+ inspects the bundle headers to check that the prerequisite commit OIDs
+ are present in the client repository. If some are missing, then the
+ client delays unbundling until other bundles have been unbundled,
+ making those OIDs present. When all required OIDs are present, the
+ client unbundles that data using a refspec. The default refspec is
+ `+refs/heads/*:refs/bundles/*`, but this can be configured. These refs
+ are stored so that later `git fetch` negotiations can communicate the
+ bundled refs as `have`s, reducing the size of the fetch over the Git
+ protocol. To allow pruning refs from this ref namespace, Git may
+ introduce a numbered namespace (such as `refs/bundles/<i>/*`) such that
+ stale bundle refs can be deleted.
+
+3. If the file is instead a bundle list, then the client inspects the
+ `bundle.mode` to see if the list is of the `all` or `any` form.
+
+ a. If `bundle.mode=all`, then the client considers all bundle
+ URIs. The list is reduced based on the `bundle.<id>.filter` options
+ matching the client repository's partial clone filter. Then, all
+ bundle URIs are requested. If the `bundle.<id>.creationToken`
+ heuristic is provided, then the bundles are downloaded in decreasing
+ order by the creation token, stopping when a bundle has all required
+ OIDs. The bundles can then be unbundled in increasing creation token
+ order. The client stores the latest creation token as a heuristic
+ for avoiding future downloads if the bundle list does not advertise
+ bundles with larger creation tokens.
+
+ b. If `bundle.mode=any`, then the client can choose any one of the
+ bundle URIs to inspect. The client can use a variety of ways to
+ choose among these URIs. The client can also fallback to another URI
+ if the initial choice fails to return a result.
+
+Note that during a clone we expect that all bundles will be required, and
+heuristics such as `bundle.<uri>.creationToken` can be used to download
+bundles in chronological order or in parallel.
+
+If a given bundle URI is a bundle list with a `bundle.heuristic`
+value, then the client can choose to store that URI as its chosen bundle
+URI. The client can then navigate directly to that URI during later `git
+fetch` calls.
+
+When downloading bundle URIs, the client can choose to inspect the initial
+content before committing to downloading the entire content. This may
+provide enough information to determine if the URI is a bundle list or
+a bundle. In the case of a bundle, the client may inspect the bundle
+header to determine that all advertised tips are already in the client
+repository and cancel the remaining download.
+
+Fetching with Bundle URIs
+-------------------------
+
+When the client fetches new data, it can decide to fetch from bundle
+servers before fetching from the origin remote. This could be done via a
+command-line option, but it is more likely useful to use a config value
+such as the one specified during the clone.
+
+The fetch operation follows the same procedure to download bundles from a
+bundle list (although we do _not_ want to use parallel downloads here). We
+expect that the process will end when all prerequisite commit OIDs in a
+thin bundle are already in the object database.
+
+When using the `creationToken` heuristic, the client can avoid downloading
+any bundles if their creation tokenss are not larger than the stored
+creation token. After fetching new bundles, Git updates this local
+creation token.
+
+If the bundle provider does not provide a heuristic, then the client
+should attempt to inspect the bundle headers before downloading the full
+bundle data in case the bundle tips already exist in the client
+repository.
+
+Error Conditions
+----------------
+
+If the Git client discovers something unexpected while downloading
+information according to a bundle URI or the bundle list found at that
+location, then Git can ignore that data and continue as if it was not
+given a bundle URI. The remote Git server is the ultimate source of truth,
+not the bundle URI.
+
+Here are a few example error conditions:
+
+* The client fails to connect with a server at the given URI or a connection
+ is lost without any chance to recover.
+
+* The client receives a 400-level response (such as `404 Not Found` or
+ `401 Not Authorized`). The client should use the credential helper to
+ find and provide a credential for the URI, but match the semantics of
+ Git's other HTTP protocols in terms of handling specific 400-level
+ errors.
+
+* The server reports any other failure reponse.
+
+* The client receives data that is not parsable as a bundle or bundle list.
+
+* A bundle includes a filter that does not match expectations.
+
+* The client cannot unbundle the bundles because the prerequisite commit OIDs
+ are not in the object database and there are no more bundles to download.
+
+There are also situations that could be seen as wasteful, but are not
+error conditions:
+
+* The downloaded bundles contain more information than is requested by
+ the clone or fetch request. A primary example is if the user requests
+ a clone with `--single-branch` but downloads bundles that store every
+ reachable commit from all `refs/heads/*` references. This might be
+ initially wasteful, but perhaps these objects will become reachable by
+ a later ref update that the client cares about.
+
+* A bundle download during a `git fetch` contains objects already in the
+ object database. This is probably unavoidable if we are using bundles
+ for fetches, since the client will almost always be slightly ahead of
+ the bundle servers after performing its "catch-up" fetch to the remote
+ server. This extra work is most wasteful when the client is fetching
+ much more frequently than the server is computing bundles, such as if
+ the client is using hourly prefetches with background maintenance, but
+ the server is computing bundles weekly. For this reason, the client
+ should not use bundle URIs for fetch unless the server has explicitly
+ recommended it through a `bundle.heuristic` value.
+
+Example Bundle Provider organization
+------------------------------------
+
+The bundle URI feature is intentionally designed to be flexible to
+different ways a bundle provider wants to organize the object data.
+However, it can be helpful to have a complete organization model described
+here so providers can start from that base.
+
+This example organization is a simplified model of what is used by the
+GVFS Cache Servers (see section near the end of this document) which have
+been beneficial in speeding up clones and fetches for very large
+repositories, although using extra software outside of Git.
+
+The bundle provider deploys servers across multiple geographies. Each
+server manages its own bundle set. The server can track a number of Git
+repositories, but provides a bundle list for each based on a pattern. For
+example, when mirroring a repository at `https://<domain>/<org>/<repo>`
+the bundle server could have its bundle list available at
+`https://<server-url>/<domain>/<org>/<repo>`. The origin Git server can
+list all of these servers under the "any" mode:
+
+ [bundle]
+ version = 1
+ mode = any
+
+ [bundle "eastus"]
+ uri = https://eastus.example.com/<domain>/<org>/<repo>
+
+ [bundle "europe"]
+ uri = https://europe.example.com/<domain>/<org>/<repo>
+
+ [bundle "apac"]
+ uri = https://apac.example.com/<domain>/<org>/<repo>
+
+This "list of lists" is static and only changes if a bundle server is
+added or removed.
+
+Each bundle server manages its own set of bundles. The initial bundle list
+contains only a single bundle, containing all of the objects received from
+cloning the repository from the origin server. The list uses the
+`creationToken` heuristic and a `creationToken` is made for the bundle
+based on the server's timestamp.
+
+The bundle server runs regularly-scheduled updates for the bundle list,
+such as once a day. During this task, the server fetches the latest
+contents from the origin server and generates a bundle containing the
+objects reachable from the latest origin refs, but not contained in a
+previously-computed bundle. This bundle is added to the list, with care
+that the `creationToken` is strictly greater than the previous maximum
+`creationToken`.
+
+When the bundle list grows too large, say more than 30 bundles, then the
+oldest "_N_ minus 30" bundles are combined into a single bundle. This
+bundle's `creationToken` is equal to the maximum `creationToken` among the
+merged bundles.
+
+An example bundle list is provided here, although it only has two daily
+bundles and not a full list of 30:
+
+ [bundle]
+ version = 1
+ mode = all
+ heuristic = creationToken
+
+ [bundle "2022-02-13-1644770820-daily"]
+ uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-09-1644770820-daily.bundle
+ creationToken = 1644770820
+
+ [bundle "2022-02-09-1644442601-daily"]
+ uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-09-1644442601-daily.bundle
+ creationToken = 1644442601
+
+ [bundle "2022-02-02-1643842562"]
+ uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-02-1643842562.bundle
+ creationToken = 1643842562
+
+To avoid storing and serving object data in perpetuity despite becoming
+unreachable in the origin server, this bundle merge can be more careful.
+Instead of taking an absolute union of the old bundles, instead the bundle
+can be created by looking at the newer bundles and ensuring that their
+necessary commits are all available in this merged bundle (or in another
+one of the newer bundles). This allows "expiring" object data that is not
+being used by new commits in this window of time. That data could be
+reintroduced by a later push.
+
+The intention of this data organization has two main goals. First, initial
+clones of the repository become faster by downloading precomputed object
+data from a closer source. Second, `git fetch` commands can be faster,
+especially if the client has not fetched for a few days. However, if a
+client does not fetch for 30 days, then the bundle list organization would
+cause redownloading a large amount of object data.
+
+One way to make this organization more useful to users who fetch frequently
+is to have more frequent bundle creation. For example, bundles could be
+created every hour, and then once a day those "hourly" bundles could be
+merged into a "daily" bundle. The daily bundles are merged into the
+oldest bundle after 30 days.
+
+It is recommened that this bundle strategy is repeated with the `blob:none`
+filter if clients of this repository are expecting to use blobless partial
+clones. This list of blobless bundles stays in the same list as the full
+bundles, but uses the `bundle.<id>.filter` key to separate the two groups.
+For very large repositories, the bundle provider may want to _only_ provide
+blobless bundles.
+
+Implementation Plan
+-------------------
+
+This design document is being submitted on its own as an aspirational
+document, with the goal of implementing all of the mentioned client
+features over the course of several patch series. Here is a potential
+outline for submitting these features:
+
+1. Integrate bundle URIs into `git clone` with a `--bundle-uri` option.
+ This will include a new `git fetch --bundle-uri` mode for use as the
+ implementation underneath `git clone`. The initial version here will
+ expect a single bundle at the given URI.
+
+2. Implement the ability to parse a bundle list from a bundle URI and
+ update the `git fetch --bundle-uri` logic to properly distinguish
+ between `bundle.mode` options. Specifically design the feature so
+ that the config format parsing feeds a list of key-value pairs into the
+ bundle list logic.
+
+3. Create the `bundle-uri` protocol v2 command so Git servers can advertise
+ bundle URIs using the key-value pairs. Plug into the existing key-value
+ input to the bundle list logic. Allow `git clone` to discover these
+ bundle URIs and bootstrap the client repository from the bundle data.
+ (This choice is an opt-in via a config option and a command-line
+ option.)
+
+4. Allow the client to understand the `bundle.flag=forFetch` configuration
+ and the `bundle.<id>.creationToken` heuristic. When `git clone`
+ discovers a bundle URI with `bundle.flag=forFetch`, it configures the
+ client repository to check that bundle URI during later `git fetch <remote>`
+ commands.
+
+5. Allow clients to discover bundle URIs during `git fetch` and configure
+ a bundle URI for later fetches if `bundle.flag=forFetch`.
+
+6. Implement the "inspect headers" heuristic to reduce data downloads when
+ the `bundle.<id>.creationToken` heuristic is not available.
+
+As these features are reviewed, this plan might be updated. We also expect
+that new designs will be discovered and implemented as this feature
+matures and becomes used in real-world scenarios.
+
+Related Work: Packfile URIs
+---------------------------
+
+The Git protocol already has a capability where the Git server can list
+a set of URLs along with the packfile response when serving a client
+request. The client is then expected to download the packfiles at those
+locations in order to have a complete understanding of the response.
+
+This mechanism is used by the Gerrit server (implemented with JGit) and
+has been effective at reducing CPU load and improving user performance for
+clones.
+
+A major downside to this mechanism is that the origin server needs to know
+_exactly_ what is in those packfiles, and the packfiles need to be available
+to the user for some time after the server has responded. This coupling
+between the origin and the packfile data is difficult to manage.
+
+Further, this implementation is extremely hard to make work with fetches.
+
+Related Work: GVFS Cache Servers
+--------------------------------
+
+The GVFS Protocol [2] is a set of HTTP endpoints designed independently of
+the Git project before Git's partial clone was created. One feature of this
+protocol is the idea of a "cache server" which can be colocated with build
+machines or developer offices to transfer Git data without overloading the
+central server.
+
+The endpoint that VFS for Git is famous for is the `GET /gvfs/objects/{oid}`
+endpoint, which allows downloading an object on-demand. This is a critical
+piece of the filesystem virtualization of that product.
+
+However, a more subtle need is the `GET /gvfs/prefetch?lastPackTimestamp=<t>`
+endpoint. Given an optional timestamp, the cache server responds with a list
+of precomputed packfiles containing the commits and trees that were introduced
+in those time intervals.
+
+The cache server computes these "prefetch" packfiles using the following
+strategy:
+
+1. Every hour, an "hourly" pack is generated with a given timestamp.
+2. Nightly, the previous 24 hourly packs are rolled up into a "daily" pack.
+3. Nightly, all prefetch packs more than 30 days old are rolled up into
+ one pack.
+
+When a user runs `gvfs clone` or `scalar clone` against a repo with cache
+servers, the client requests all prefetch packfiles, which is at most
+`24 + 30 + 1` packfiles downloading only commits and trees. The client
+then follows with a request to the origin server for the references, and
+attempts to checkout that tip reference. (There is an extra endpoint that
+helps get all reachable trees from a given commit, in case that commit
+was not already in a prefetch packfile.)
+
+During a `git fetch`, a hook requests the prefetch endpoint using the
+most-recent timestamp from a previously-downloaded prefetch packfile.
+Only the list of packfiles with later timestamps are downloaded. Most
+users fetch hourly, so they get at most one hourly prefetch pack. Users
+whose machines have been off or otherwise have not fetched in over 30 days
+might redownload all prefetch packfiles. This is rare.
+
+It is important to note that the clients always contact the origin server
+for the refs advertisement, so the refs are frequently "ahead" of the
+prefetched pack data. The missing objects are downloaded on-demand using
+the `GET gvfs/objects/{oid}` requests, when needed by a command such as
+`git checkout` or `git log`. Some Git optimizations disable checks that
+would cause these on-demand downloads to be too aggressive.
+
+See Also
+--------
+
+[1] https://lore.kernel.org/git/RFC-cover-00.13-0000000000-20210805T150534Z-avarab@gmail.com/
+ An earlier RFC for a bundle URI feature.
+
+[2] https://github.com/microsoft/VFSForGit/blob/master/Protocol.md
+ The GVFS Protocol
diff --git a/technical/cruft-packs.txt b/technical/cruft-packs.txt
deleted file mode 100644
index d81f3a898..000000000
--- a/technical/cruft-packs.txt
+++ /dev/null
@@ -1,123 +0,0 @@
-= Cruft packs
-
-The cruft packs feature offer an alternative to Git's traditional mechanism of
-removing unreachable objects. This document provides an overview of Git's
-pruning mechanism, and how a cruft pack can be used instead to accomplish the
-same.
-
-== Background
-
-To remove unreachable objects from your repository, Git offers `git repack -Ad`
-(see linkgit:git-repack[1]). Quoting from the documentation:
-
-[quote]
-[...] unreachable objects in a previous pack become loose, unpacked objects,
-instead of being left in the old pack. [...] loose unreachable objects will be
-pruned according to normal expiry rules with the next 'git gc' invocation.
-
-Unreachable objects aren't removed immediately, since doing so could race with
-an incoming push which may reference an object which is about to be deleted.
-Instead, those unreachable objects are stored as loose objects and stay that way
-until they are older than the expiration window, at which point they are removed
-by linkgit:git-prune[1].
-
-Git must store these unreachable objects loose in order to keep track of their
-per-object mtimes. If these unreachable objects were written into one big pack,
-then either freshening that pack (because an object contained within it was
-re-written) or creating a new pack of unreachable objects would cause the pack's
-mtime to get updated, and the objects within it would never leave the expiration
-window. Instead, objects are stored loose in order to keep track of the
-individual object mtimes and avoid a situation where all cruft objects are
-freshened at once.
-
-This can lead to undesirable situations when a repository contains many
-unreachable objects which have not yet left the grace period. Having large
-directories in the shards of `.git/objects` can lead to decreased performance in
-the repository. But given enough unreachable objects, this can lead to inode
-starvation and degrade the performance of the whole system. Since we
-can never pack those objects, these repositories often take up a large amount of
-disk space, since we can only zlib compress them, but not store them in delta
-chains.
-
-== Cruft packs
-
-A cruft pack eliminates the need for storing unreachable objects in a loose
-state by including the per-object mtimes in a separate file alongside a single
-pack containing all loose objects.
-
-A cruft pack is written by `git repack --cruft` when generating a new pack.
-linkgit:git-pack-objects[1]'s `--cruft` option. Note that `git repack --cruft`
-is a classic all-into-one repack, meaning that everything in the resulting pack is
-reachable, and everything else is unreachable. Once written, the `--cruft`
-option instructs `git repack` to generate another pack containing only objects
-not packed in the previous step (which equates to packing all unreachable
-objects together). This progresses as follows:
-
- 1. Enumerate every object, marking any object which is (a) not contained in a
- kept-pack, and (b) whose mtime is within the grace period as a traversal
- tip.
-
- 2. Perform a reachability traversal based on the tips gathered in the previous
- step, adding every object along the way to the pack.
-
- 3. Write the pack out, along with a `.mtimes` file that records the per-object
- timestamps.
-
-This mode is invoked internally by linkgit:git-repack[1] when instructed to
-write a cruft pack. Crucially, the set of in-core kept packs is exactly the set
-of packs which will not be deleted by the repack; in other words, they contain
-all of the repository's reachable objects.
-
-When a repository already has a cruft pack, `git repack --cruft` typically only
-adds objects to it. An exception to this is when `git repack` is given the
-`--cruft-expiration` option, which allows the generated cruft pack to omit
-expired objects instead of waiting for linkgit:git-gc[1] to expire those objects
-later on.
-
-It is linkgit:git-gc[1] that is typically responsible for removing expired
-unreachable objects.
-
-== Caution for mixed-version environments
-
-Repositories that have cruft packs in them will continue to work with any older
-version of Git. Note, however, that previous versions of Git which do not
-understand the `.mtimes` file will use the cruft pack's mtime as the mtime for
-all of the objects in it. In other words, do not expect older (pre-cruft pack)
-versions of Git to interpret or even read the contents of the `.mtimes` file.
-
-Note that having mixed versions of Git GC-ing the same repository can lead to
-unreachable objects never being completely pruned. This can happen under the
-following circumstances:
-
- - An older version of Git running GC explodes the contents of an existing
- cruft pack loose, using the cruft pack's mtime.
- - A newer version running GC collects those loose objects into a cruft pack,
- where the .mtime file reflects the loose object's actual mtimes, but the
- cruft pack mtime is "now".
-
-Repeating this process will lead to unreachable objects not getting pruned as a
-result of repeatedly resetting the objects' mtimes to the present time.
-
-If you are GC-ing repositories in a mixed version environment, consider omitting
-the `--cruft` option when using linkgit:git-repack[1] and linkgit:git-gc[1], and
-leaving the `gc.cruftPacks` configuration unset until all writers understand
-cruft packs.
-
-== Alternatives
-
-Notable alternatives to this design include:
-
- - The location of the per-object mtime data, and
- - Storing unreachable objects in multiple cruft packs.
-
-On the location of mtime data, a new auxiliary file tied to the pack was chosen
-to avoid complicating the `.idx` format. If the `.idx` format were ever to gain
-support for optional chunks of data, it may make sense to consolidate the
-`.mtimes` format into the `.idx` itself.
-
-Storing unreachable objects among multiple cruft packs (e.g., creating a new
-cruft pack during each repacking operation including only unreachable objects
-which aren't already stored in an earlier cruft pack) is significantly more
-complicated to construct, and so aren't pursued here. The obvious drawback to
-the current implementation is that the entire cruft pack must be re-written from
-scratch.
diff --git a/technical/hash-function-transition.html b/technical/hash-function-transition.html
index 62f1b52ea..1874731c0 100644
--- a/technical/hash-function-transition.html
+++ b/technical/hash-function-transition.html
@@ -1044,7 +1044,7 @@ SHA-1 content.</p></div>
<div class="sect2">
<h3 id="_object_storage">Object storage</h3>
<div class="paragraph"><p>Loose objects use zlib compression and packed objects use the packed
-format described in Documentation/technical/pack-format.txt, just like
+format described in <a href="../gitformat-pack.html">gitformat-pack(5)</a>, just like
today. The content that is compressed and stored uses SHA-256 content
instead of SHA-1 content.</p></div>
</div>
@@ -2087,7 +2087,7 @@ See the history of this file in git.git for the history of subsequent
<div id="footer">
<div id="footer-text">
Last updated
- 2021-07-14 15:10:10 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/technical/hash-function-transition.txt b/technical/hash-function-transition.txt
index 260224b03..e2ac36dd2 100644
--- a/technical/hash-function-transition.txt
+++ b/technical/hash-function-transition.txt
@@ -205,7 +205,7 @@ SHA-1 content.
Object storage
~~~~~~~~~~~~~~
Loose objects use zlib compression and packed objects use the packed
-format described in Documentation/technical/pack-format.txt, just like
+format described in linkgit:gitformat-pack[5], just like
today. The content that is compressed and stored uses SHA-256 content
instead of SHA-1 content.
diff --git a/technical/long-running-process-protocol.html b/technical/long-running-process-protocol.html
index 410ec6d23..777db24f2 100644
--- a/technical/long-running-process-protocol.html
+++ b/technical/long-running-process-protocol.html
@@ -741,7 +741,7 @@ asciidoc.install();
<div class="sectionbody">
<div class="paragraph"><p>This protocol is used when Git needs to communicate with an external
process throughout the entire life of a single Git command. All
-communication is in pkt-line format (see technical/protocol-common.txt)
+communication is in pkt-line format (see <a href="../gitprotocol-common.html">gitprotocol-common(5)</a>)
over standard input and standard output.</p></div>
</div>
</div>
@@ -795,7 +795,7 @@ process has stopped.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2020-03-10 15:02:33 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/technical/long-running-process-protocol.txt b/technical/long-running-process-protocol.txt
index aa0aa9af1..6f33654b4 100644
--- a/technical/long-running-process-protocol.txt
+++ b/technical/long-running-process-protocol.txt
@@ -3,7 +3,7 @@ Long-running process protocol
This protocol is used when Git needs to communicate with an external
process throughout the entire life of a single Git command. All
-communication is in pkt-line format (see technical/protocol-common.txt)
+communication is in pkt-line format (see linkgit:gitprotocol-common[5])
over standard input and standard output.
Handshake
diff --git a/technical/packfile-uri.txt b/technical/packfile-uri.txt
index 1eb525fe7..9d453d476 100644
--- a/technical/packfile-uri.txt
+++ b/technical/packfile-uri.txt
@@ -18,7 +18,7 @@ a `packfile-uris` argument, the server MAY send a `packfile-uris` section
directly before the `packfile` section (right after `wanted-refs` if it is
sent) containing URIs of any of the given protocols. The URIs point to
packfiles that use only features that the client has declared that it supports
-(e.g. ofs-delta and thin-pack). See protocol-v2.txt for the documentation of
+(e.g. ofs-delta and thin-pack). See linkgit:gitprotocol-v2[5] for the documentation of
this section.
Clients should then download and index all the given URIs (in addition to
diff --git a/technical/partial-clone.html b/technical/partial-clone.html
index ba91f11e8..c0317939c 100644
--- a/technical/partial-clone.html
+++ b/technical/partial-clone.html
@@ -837,7 +837,7 @@ A new pack-protocol capability "filter" is added to the fetch-pack and
upload-pack negotiation.
</p>
<div class="paragraph"><p>This uses the existing capability discovery mechanism.
-See "filter" in Documentation/technical/pack-protocol.txt.</p></div>
+See "filter" in <a href="../gitprotocol-pack.html">gitprotocol-pack(5)</a>.</p></div>
</li>
<li>
<p>
@@ -1213,7 +1213,7 @@ type of packfile that references it.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2022-04-04 11:19:32 PDT
+ 2022-08-18 14:11:07 PDT
</div>
</div>
</body>
diff --git a/technical/partial-clone.txt b/technical/partial-clone.txt
index 99f0eb304..92fcee2bf 100644
--- a/technical/partial-clone.txt
+++ b/technical/partial-clone.txt
@@ -79,7 +79,7 @@ Design Details
upload-pack negotiation.
+
This uses the existing capability discovery mechanism.
-See "filter" in Documentation/technical/pack-protocol.txt.
+See "filter" in linkgit:gitprotocol-pack[5].
- Clients pass a "filter-spec" to clone and fetch which is passed to the
server to request filtering during packfile construction.
diff --git a/user-manual.html b/user-manual.html
index e5b89c596..0bee55c8a 100644
--- a/user-manual.html
+++ b/user-manual.html
@@ -1393,7 +1393,7 @@ individual files. The second is the amount of space taken up by
those "loose" objects.</p><p>You can save space and make Git faster by moving these loose objects in
to a "pack file", which stores a group of objects in an efficient
compressed format; the details of how pack files are formatted can be
-found in <a class="ulink" href="technical/pack-format.html" target="_top">pack format</a>.</p><p>To put the loose objects into a pack, just run git repack:</p><pre class="screen">$ git repack
+found in <a class="ulink" href="gitformat-pack" target="_top">5</a>.</p><p>To put the loose objects into a pack, just run git repack:</p><pre class="screen">$ git repack
Counting objects: 6020, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6020/6020), done.
diff --git a/user-manual.txt b/user-manual.txt
index 865074bed..ca9decdd9 100644
--- a/user-manual.txt
+++ b/user-manual.txt
@@ -3133,7 +3133,7 @@ those "loose" objects.
You can save space and make Git faster by moving these loose objects in
to a "pack file", which stores a group of objects in an efficient
compressed format; the details of how pack files are formatted can be
-found in link:technical/pack-format.html[pack format].
+found in link:gitformat-pack[5].
To put the loose objects into a pack, just run git repack: